Git
Chapters ▾ 2nd Edition

8.1 Настройване на Git - Git конфигурации

Досега прегледахме основите на работата с Git, представихме и множество инструменти, помагащи ни да работим по-лесно и ефективно. В тази глава ще видим как да накараме Git да работи в по-специфични режими посредством няколко важни конфигурационни настройки и hooks системата. С тези инструменти е лесно да накарате Git да работи точно както желаете вие, вашия екип или компанията ви.

Git конфигурации

Както погледнахме накратко в Начало, можете да използвате командата git config за манипулация на конфигурационни настройки. Едно от първите неща, които направихме беше да зададем име и имейл адрес:

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

Сега ще разгледаме повече интересни опции, които можем да променяме по този начин, така че да настроим по-фино поведението на Git системата.

Първо, кратък преглед: Git използва серия от конфигурационни файлове, за да определи нестандартното поведение, което бихте могли да искате. Първото място, което Git проверява, е system-wide файла /etc/gitconfig, който съдържа множество настройки валидни за всички потребители и всички хранилища в машината. Ако подадете опцията --system на git config, командата чете и пише точно в този файл.

След това Git търси файла ~/.gitconfig (или ~/.config/git/config) в потребителските директории, в който се съхраняват настройки специално за конкретния потребител на операционната система. Този е засегнатия файл, когато подавате на командата аргумента --global.

Най-накрая Git проверява за конфигурационни настройки във файл в конкретното текущо хранилище (.git/config). Тези стойности са специфични само за конкретното хранилище и се подават с аргумента --local към git config. (Ако не укажете аргумент за обхват на командата, именно това локално ниво се използва по подразбиране.)

Всяко от тези “нива” (system, global, local) презаписва стойностите от предишното, така че стойностите в .git/config са с приоритет пред тези в /etc/gitconfig, например.

Note

Конфигурационните файлове на Git са чист текст и можете да редактирате файловете директно, спазвайки съответния синтаксис. Все пак, вероятно е по-лесно да използвате git config.

Основни конфигурации на клиента

Конфигурационните опции, които Git използва попадат в две главни категории: клиентска и сървърна. Болшинството от опции са клиентски — настройват персоналните ви предпочитания за работа. Поддържат се огромен брой опции, но голяма част от тях се използват само в специфични случаи, ето защо ще разгледаме най-популярните и полезни. Ако искате списък на всички, можете да изпълните

$ man git-config

Тази команда изброява и обяснява всички налични опции в подробности. Алтернативно място да получите тази информация е http://git-scm.com/docs/git-config.html.

core.editor

По подразбиране, Git използва настро̀ения за вашия персонален акаунт текстов редактор през environment променливите VISUAL или EDITOR и ако такъв няма, използва vi за манипулация на къмит съобщенията и таговете. Ако искате да промените редактора, използвайте настройката `core.editor:

$ git config --global core.editor emacs

След това, без оглед на подразбиращия се шел редактор, Git ще стартира Emacs за редакция на съобщенията.

commit.template

Ако настроите тази опция да сочи към файл в компютъра, Git ще използва съдържанието на този файл като подразбиращо се начално съобщение когато къмитвате. Предимството в това да имате шаблон е, че можете да го използвате като припомяне за вас (а и за останалите) как да се пишат и форматират добри къмит съобщения.

Например, имаме файла ~/.gitmessage.txt:

Subject line (try to keep under 50 characters)

Multi-line description of commit,
feel free to be detailed.

[Ticket: X]

Забелязваме как този шаблон припомня на разработчика да поддържа subject реда кратък (за по-красив git log --oneline изход), да добавя подробности под него и да упоменава issue или номер на тикет в bug tracker система, ако има такава.

Задаването на шаблона се прави с командата:

$ git config --global commit.template ~/.gitmessage.txt
$ git commit

След което, текстовият редактор ще изглежда така, когато бъде стартиран:

Subject line (try to keep under 50 characters)

Multi-line description of commit,
feel free to be detailed.

[Ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C

Ако екипът ви спазва commit-message политика, тогава използването на един такъв шаблон би било много полезно и увеличава шансовете за стриктно спазване на политиката.

core.pager

Тази настройка определя кой пейджър да се използва, когато Git странира изхода от команди като log и diff. Можете да я настроите на more или на нещо друго (по подразбиране е less), а също и можете да изключите странирането задавайки ѝ празен стринг:

$ git config --global core.pager ''

Така Git ще показва наведнъж целия изход от всички команди без значение от дължината му.

user.signingkey

Ако правите signed annotated тагове (както видяхме в Подписване на вашата работа), задаването на вашия GPG подписващ ключ като конфигурационна настройка, ще ви спести писане. Задава се така:

$ git config --global user.signingkey <gpg-key-id>

Сега можете да подписвате тагове без да трябва да указвате ключа си всеки път, когато пуснете git tag:

$ git tag -s <tag-name>

core.excludesfile

В Игнориране на файлове видяхме как да създаваме маски в .gitignore файл, така че Git да не вижда и да не се опитва да индексира определени файлове в проекта.

Понякога обаче е по-удобно да игнорирате дадени файлове във всички хранилища, с които работите. Ако използвате macOS, вероятно сте запознати с .DS_Store файловете. Ако предпочитаният ви редактор е Emacs или Vim, знаете за файловите имена, които завършват на ~ или .swp.

Тази настройка дава възможност за нещо като глобален .gitignore файл. Ако създадете файл ~/.gitignore_global с това съдържание:

*~
.*.swp
.DS_Store

…и изпълните git config --global core.excludesfile ~/.gitignore_global, Git въобще няма да обръща внимание на подобни файлове във всички хранилища.

help.autocorrect

Ако сбъркате команда, Git показва нещо от рода:

$ git chekcout master
git: 'chekcout' is not a git command. See 'git --help'.

Did you mean this?
    checkout

Услужливо ви предлага да отгатне какво имате предвид, но все пак не изпълнява предполагаемата команда. Ако обаче зададете help.autocorrect със стойност 1, Git ще изпълни командата:

$ git chekcout master
WARNING: You called a Git command named 'chekcout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...

Забележете съобщението “0.1 seconds”. help.autocorrect стойността в действителност е цяло число, което представлява десета от секундата. Така че, ако го промените на 50, Git ще ви даде 5 секунди да размислите преди да стартира командата, която предполага че искате.

Цветове в Git

Git има пълна поддръжка за цветен изход в терминала, което помага много за лесното разчитане на информацията от потребителя. Имате множество опции за настройка на цветните предпочитания.

color.ui

Git автоматично оцветява повечето от изхода на командите си, но разполагате с главен ключ, ако не искате това. За да изключите всякакво оцветяване, изпълнете:

$ git config --global color.ui false

Стойността по подразбиране е auto, което оцветява изхода в терминала, но пропуска color-control кодовете, ако изходът е пренасочен към pipe или към файл.

Ако искате оцветяване навсякъде, настройката също приема и стойността always. Вероятно малко хора ще искат да правят това, в повечето случаи ако искате цветове в пренасочения изход, можете да подадете флага --color към конкретната единична команда. В почти всички случаи настройките по подразбиране ще са това, което очаквате.

color.*

Можете да бъдете и още по-прецизни в избора на това изходът от кои команди да се оцветява и как точно. Всяка от тези опции може да е true, false, или always:

color.branch
color.diff
color.interactive
color.status

В допълнение, всяка от тях има и поднастройки, които можете да използвате за да задавате специфични цветове на част от изхода им и да коригирате всеки един от зададените цветове. Например, ако искате метаданните във вашия diff изход да са със сини символи на черен фон и удебелен шрифт, може да направите така

$ git config --global color.diff.meta "blue black bold"

Цветовете приемат стойности: normal, black, red, green, yellow, blue, magenta, cyan, или white. Ако искате специфичен атрибут за шрифта както беше bold преди малко, налични са вариантите bold, dim, ul (underline), blink, и reverse (размяна на цветовете на символите и фона).

Външни Merge и Diff инструменти

Въпреки, че Git има собствена вътрешна diff имплементация (която виждаме в действие в настоящата книга), можете да използвате и външен diff инструмент. Можете да си настроите графичен merge-conflict-resolution инструмент, вместо да трябва да коригирате конфликтите ръчно. Ще покажем как се настройва безплатния и удобен инструмент Perforce Visual Merge Tool (P4Merge) за да правите вашите diffs и merge resolutions.

Ако искате да го пробвате, P4Merge работи на всички основни платформи. В примерите ще използваме пътища, които се ползват в Mac и Linux, за Windows ще трябва да смените /usr/local/bin към съответния път в конкретната инсталация.

За начало, изтеглете P4Merge от Perforce. След това, ще създадем външни wrapper скриптове за изпълнение на командите ви. Ще използваме Mac пътя за изпълнимия файл, в други системи той ще е мястото, където се намира p4merge програмата. Създаваме merge wrapper скрипт наречен extMerge, който извиква програмата с всички необходими аргументи:

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*

Скриптът за diff от своя страна проверява за подадени седем аргумента и изпраща два от тях към merge скрипта. По подразбиране, Git изпраща следните аргументи към diff програмата:

path old-file old-hex old-mode new-file new-hex new-mode

Понеже искаме само old-file и new-file аргументите, използваме wrapper скрипта, за да подаваме само тях.

$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"

Тези скриптове трябва да са изпълними:

$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff

Сега можем да използваме конфигурационния си файл да използва тези потребителски инструменти. Приемат се множество специфични настройки: merge.tool за да кажем на Git каква стратегия на сливане да ползва, mergetool.<tool>.cmd за начина на стартиране на командата, mergetool.<tool>.trustExitCode за да укажем на Git, че кода на изход на програмата индикира успешно/неуспешно сливане, и diff.external за командата използвана за diff. Така може да изпълните следните 4 конфигурационни команди

$ git config --global merge.tool extMerge
$ git config --global mergetool.extMerge.cmd \
  'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
$ git config --global mergetool.extMerge.trustExitCode false
$ git config --global diff.external extDiff

или пък директно да редактирате ~/.gitconfig файла така:

[merge]
  tool = extMerge
[mergetool "extMerge"]
  cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
  trustExitCode = false
[diff]
  external = extDiff

Ако всичко това е направено и изпълните diff команда като тази:

$ git diff 32d1776b1^ 32d1776b1

Вместо да видите изхода на командния ред, Git ще стартира P4Merge, който би изглеждал подобно:

P4Merge.
Figure 143. P4Merge.

Ако опитате да слеете два клона и получите конфликти, може да изпълните git mergetool и тя от своя страна ще стартира P4Merge за да ви позволи да ги разрешите в графичен стил.

Удобното нещо на тези wrapper настройки е, че лесно можете да променяте diff и merge инструментите си. Например, ако желаете extDiff и extMerge скриптовете да пускат KDiff3 програмата, просто трябва да редактирате файла extMerge:

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*

Сега вече Git ще използва KDiff3 за показване на diff информация и разрешаване на конфликти.

Git също така идва с известен брой предварително зададени външни merge-resolution инструменти за да не се налага да правите командната конфигурация. За да видите списък с тях, пробвайте това:

$ git mergetool --tool-help
'git mergetool --tool=<tool>' may be set to one of the following:
        emerge
        gvimdiff
        gvimdiff2
        opendiff
        p4merge
        vimdiff
        vimdiff2

The following tools are valid, but not currently available:
        araxis
        bc3
        codecompare
        deltawalker
        diffmerge
        diffuse
        ecmerge
        kdiff3
        meld
        tkdiff
        tortoisemerge
        xxdiff

Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.

Ако не се интересувате от KDiff3 за diff, но искате да го използвате за корекция на конфликти и kdiff3 командата е в пътя ви, можете да изпълните

$ git config --global merge.tool kdiff3

Ако направите това вместо да създавате extMerge и extDiff скриптовете, Git ще ползва KDiff3 за конфликти и вътрешния Git diff инструмент за diff визуализация.

Форматиране и празни символи

Проблемите с форматирането и празните символи са сред най-досадните неща, с които разработчиците се сблъскват по време на съвместна работа и особено ако работят на различни платформи. Много е лесно пачове или друга съвместна работа да внесат незабележими whitespace промени, защото редакторите ги вкарват задкулисно и ако файловете ви се озоват на Windows система, знаците им за край на ред може да се променят без предупреждение. Git разполага с няколко конфигурационни опции за да ви помогне в такива случаи.

core.autocrlf

Ако програмирате под Windows, а колегите ви не (или обратното), твърде вероятно е да възникнат проблемни ситуации в даден етап. Това е защото Windows използва за край на ред във файловете и двата символа (carriage-return character и linefeed), докато под Mac/Linux се използва само linefeed. Това е незабележима за окото разлика, но постоянно предизвиква проблеми при многоплатформена работа, много редактори под Windows без да питат конвертират наличните LF знаци за край на ред в CRLF.

Git може да се справи с това конвертирайки CRLF символите в LF, когато добавяте файл в индекса и обратното, когато извличате файл в работната директория. Може да контролирате това поведение през настройката core.autocrlf. Ако сте на Windows машина, задайте true — това ще конвертира LF символите в CRLF, когато извличате файловете:

$ git config --global core.autocrlf true

Ако сте на Linux или Mac, няма да искате автоматично конвертиране, обаче ако някой файл с CRLF внезапно се появи, бихте желали Git да го коригира. Можете да зададете CRLF към LF конвертирането да се прави при къмит със стойността input за core.autocrlf:

$ git config --global core.autocrlf input

Това положение би трябвало да остави CRLF символите, когато извличате под Windows и LF символите под Mac и Linux, както и в хранилището.

Ако сте Windows програмист и работите по Windows проект, тогава може да изключите тази функционалност и да записвате CR символите в хранилището задавайки false за опцията:

$ git config --global core.autocrlf false

core.whitespace

Git също така разполага с възможност да разпознава и коригира някои проблеми с празните символи. Налични са инструменти за 6 главни ситуации — три са разрешени по подразбиране и могат да се изключат и три други по подразбиране са изключени, но могат да се активират.

Трите включени опции са blank-at-eol, която търси за интервали в края на ред; blank-at-eof, която усеща празни редове в края на файла, и space-before-tab търсеща за интервали преди табулации в началото на редовете.

Изключените фабрично опции са indent-with-non-tab, която търси редове започващи с интервали вместо с табулации (и се контролира с tabwidth опцията); tab-in-indent, която следи за наличието на табулации в indentation частта на редовете; и cr-at-eol, която казва на Git, че carriage return символите в края на редовете са OK.

Можете да кажете на Git кои от тези опции искате да са активни задавайки за core.whitespace стойностите, които искате да са включени/изключени, разделени със запетаи. Може да забраните опция добавяйки - преди името ѝ или да изисквате стойността по подразбиране като въобще не я включвате в стринга. Например, ако искате задаване на всички без space-before-tab, може да направите това (trailing-space е съкратено изписване за blank-at-eol и blank-at-eof):

$ git config --global core.whitespace \
    trailing-space,-space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol

Или, може да укажете само специфичните промени:

$ git config --global core.whitespace \
    -space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol

Git ще намери проблемите при изпълнение на git diff и ще опита да ги оцвети така че да пробвате да ги поправите преди да къмитнете. Тези стойности се използват за ваше улеснение и когато прилагате пачове с git apply. Ако прилагате пачове, може да укажете на Git да ви предупреждава, ако те съдържат whitespace проблеми:

$ git apply --whitespace=warn <patch>

Или може да кажете на Git да се опита автоматично да ги реши преди да приложи пача:

$ git apply --whitespace=fix <patch>

Тези опции важат и за командата git rebase. Ако сте къмитнали whitespace нередности, но все още не сте публикували в upstream хранилището, можете да изпълните git rebase --whitespace=fix и така Git ще се опита да коригира нещата по същия начин, по който пренаписва пачовете.

Сървърни конфигурации

Конфигурационните опции за сървърната роля на Git не са толкова много на брой, но някои от тях заслужават да бъдат посочени.

receive.fsckObjects

Git може да проверява дали всеки обект получен по време на публикуване все още съответства на очакваната си SHA-1 стойност и дали сочи към валидни обекти. Но това по подразбиране не се прави, защото е ресурсоемка операция и може да причини забавяне при големи хранилища. Може да включите проверката задавайки true за receive.fsckObjects:

$ git config --system receive.fsckObjects true

Сега Git при всеки push ще проверява интегритета на хранилището преди да го приеме, така че некоректните (или умишлено злонамерени) клиенти да не могат да внесат повредени данни.

receive.denyNonFastForwards

Ако пребазирате къмити, които вече сте публикували и се опитате да ги публикувате пак, или пък се опитате да публикувате къмит към отдалечен клон и този къмит не съдържа къмита, към който този клон текущо сочи, ще ви бъде отказано. Това по принцип е добра политика, но в случая на rebase може да установите, че знаете какво точно правите и може да форсирате обновяването на отдалечения клон с -f флага на push командата.

Може да забраните форсираните публикувания задавайки receive.denyNonFastForwards:

$ git config --system receive.denyNonFastForwards true

Друг начин да направите това е чрез сървърни receive hooks, които ще разгледаме накратко. Този подход позволява да правим много по-сложни неща като например отказ за non-fast-forwards само за определени потребители.

receive.denyDeletes

По-напредналите потребители могат да заобиколят denyNonFastForwards политиките изтривайки клона и след това публикувайки го отново с новата референция. За да избегнете това, задайте receive.denyDeletes със стойност true:

$ git config --system receive.denyDeletes true

Това забранява изтриването на клонове и тагове — никой потребител няма да може да го прави. За да изтриете отдалечени клонове ще трябва да изтриете ref файловете от сървъра ръчно. Съществуват и по-интересни начини да правите това на per-user принцип през ACL, както ще видим в Примерна Git-Enforced политика.