Git
Chapters ▾ 2nd Edition

8.1 Dostosowywanie Gita - Konfiguracja Gita

Do tej pory opisałem podstawowe rzeczy związane z działaniem i użytkowaniem Gita, oraz pokazałem kilka narzędzi dostarczanych przez Git, ułatwiających i usprawniających pracę. W tym rozdziale, przejdziemy przez funkcjonalności których możesz użyć, aby Git działał w bardziej dostosowany do Twoich potrzeb sposób, pokazując kilka ważnych ustawień oraz system hooków. Przy pomocy tych narzędzi, łatwo można spowodować, aby Git działał w dokładnie taki sposób w jaki Ty, Twoja firma lub grupa potrzebujecie.

Konfiguracja Gita

Jak w skrócie zobaczyłeś w rozdziale Pierwsze kroki, możesz zmieniać ustawienia konfiguracyjne za pomocą komendy git config Jedną z pierwszych rzeczy którą zrobiłeś, było ustawienie imienia i adresu e-mail:

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

Teraz poznasz kilka bardziej interesujących opcji, które możesz ustawić w ten sposób, aby dostosować działanie Gita.

Na początek szybka powtórka: Git używa kilku plików konfiguracyjnych, aby odczytać niestandardowe ustawienia, które możesz mieć ustawione. Pierwszym miejscem w którym Git sprawdzi te ustawienia jest plik /etc/gitconfig, który zawiera ustawienia dla wszystkich użytkowników znajdujących się w systemie, oraz dla ich wszystkich repozytoriów. Jeżeli dodasz opcję --system do git config, Git będzie zapisywał i odczytywał ustawienia właśnie z tego pliku.

Następnym miejscem w które Git zajrzy jest plik ~/.gitconfig (lub ~/.config/git/config), wskazujący na ustawienia dla konkretnych użytkowników. Dodając opcję --global, zmusisz Gita to odczytywania i zapisywania ustawień z tego pliku.

Na końcu, Git szuka ustawień w pliku konfiguracyjnym znajdującym się z katalogu Git (.git/config) w każdym repozytorium którego obecnie używasz. Ustawienia te są specyficzne dla tego konkretnego repozytorium.

Każdy z tych poziomów (systemowy system, globalny global i lokalny local) nadpisuje ustawienia poprzedniego poziomu, więc na przykład ustawienia w .git/config nadpisują te z /etc/gitconfig.

Note

Pliki konfiguracyjne Gita są tekstowe, więc możesz również ustawić te wartości poprzez ręczną edycję pliku i wstawienie odpowiedniej składni. Ogólnie rzecz biorąc, łatwiej jest jednak uruchomić komendę git config.

Podstawowa konfiguracja klienta

Opcje konfiguracyjne rozpoznawane przez Gita dzielą się na dwie kategorie: opcje klienta i serwera. Większość opcji dotyczy konfiguracji klienta – ustawień Twoich własnych preferencji. Obsługiwanych jest wiele, wiele opcji konfiguracyjnych, ale duża część z nich jest przydatna tylko w niektórych ekstremalnych przypadkach. Omówimy tu tylko te najczęściej spotykane i najbardziej przydatne. Jeżeli chcesz zobaczyć listę wszystkich opcji konfiguracyjnych które Twoja wersja Gita rozpoznaje, uruchom:

$ man git-config

To polecenie wyświetla listę wszystkich dostępnych opcji z dość dużą ilością szczegółów. Ten materiał pomocniczy możesz również znaleźć na stronie http://git-scm.com/docs/git-config.html.

core.editor

Domyślnie Git używa tego, co ustawiliśmy jako domyślny edytor tekstu ($VISUAL lub $EDITOR) lub w sytuacji awaryjnej wraca do edytora vi podczas tworzenia i edycji wiadomości commit i etykiet. Aby zmienić to domyślne ustawienie na inne, możesz użyć ustawienia core.editor:

$ git config --global core.editor emacs

Teraz, bez względu na to, co jest ustawione jako domyślny edytor powłoki, Git uruchomi Emacsa do edycji wiadomości.

commit.template

Jeżeli ustawisz ją na ścieżkę wskazującą na plik w Twoim systemie, Git będzie używał tego pliku jako szablonu komentarza do commita. Na przykład, załóżmy że stworzyłeś plik ~/.gitmessage.txt o następującej treści:

subject line

what happened

[ticket: X]

Aby wskazać Gitowi, że chcesz używać go jako domyślnej treści komentarza pokazującej się w edytorze po uruchomieniu git commit, ustaw zmienną konfiguracyjną commit.template na:

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

Dzięki temu Twój edytor będzie ustawiał coś takiego jako domyślną treść komentarza po commicie:

subject line

what happened

[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

Jeżeli masz specjalną politykę tworzenia treści komentarzy, to ustawienie takiego szablonu i skonfigurowanie Gita aby go używał zwiększy szanse na to, że będzie ona regularnie przestrzegana.

core.pager

To ustawienie określa, który program do stronicowania jest używany, gdy Git wypisuje kolejne strony tekstu przy pomocy takich poleceń jak log i diff. Możesz ustawić tutaj more lub swój inny ulubiony program (domyślnie jest to less); ewentualnie możesz go wyłączyć ustawiając pusty łańcuch znaków:

$ git config --global core.pager ''

Jeżeli uruchomisz powyższą komendę, to Git będzie pokazywał pełne wyniki wszystkich komend, bez względu na to jak są one długie.

user.signingkey

Jeżeli tworzysz opisane etykiety (jak opisano w sekcji Signing Your Work), ustawienie Twojego klucza GPG jako zmiennej konfiguracyjnej ułatwi trochę sprawę. Ustaw swój identyfikator klucza w ten sposób:

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

Teraz, możesz podpisywać tagi bez konieczności wskazywania za każdym razem klucza podczas uruchamiania komendy git tag:

$ git tag -s <tag-name>

core.excludesfile

Możesz umieścić wzorce w pliku .gitignore w swoim projekcie, aby Git nie śledził ich i nie próbował dodawać do przechowalni po wykonaniu komendy git add, jak wspomnieliśmy już w sekcji Ignorowanie plików.

Czasami jednak chcesz zignorować pewne pliki dla wszystkich repozytoriów, z którymi pracujesz. Jeśli Twój komputer pracuje pod kontrolą systemu Mac OS X, prawdopodobnie znasz pliki .DS_Store. Jeśli Twoim preferowanym edytorem jest Emacs lub Vim, wiesz o plikach kończących się znakiem ~.

To ustawienie pozwala na napisanie czegoś w rodzaju globalnego pliku .gitignore. Jeśli utworzysz plik ~/.gitignore_global z poniższą zawartością:

*~
.DS_Store

…i uruchomisz git config --global core.excludesfile ~/.gitignore_global, Git nigdy więcej nie będzie zawracał ci głowy tymi plikami.

help.autocorrect

Jeżeli błędnie wpiszesz komendę w Git, zostanie Ci pokazany wynik podobny do:

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

Did you mean this?
    checkout

Git pomocnie próbuje dowiedzieć się co miałeś na myśli, ale nadal nie chce tego zrobić. Jeśli ustawisz help.autocorrect na 1, Git faktycznie wykona tę komendę za Ciebie:

$ 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...

Zwróć uwagę na fragment "0.1 seconds". Opcja help.autocorrect jest w rzeczywistości liczbą całkowitą, która reprezentuje dziesiąte części sekundy. Jeśli więc ustawisz ją na 50, Git da ci 5 sekund na zmianę zdania przed wykonaniem polecenia z autokorekty.

Kolory w Git

Git może również pokazywać wyniki swojego działania w kolorze, co ułatwi Ci ich odczytanie w szybszy i łatwiejszy sposób. Liczne opcje pozwalają na dostosowanie kolorowania do Twoich preferencji.

color.ui

Git automatycznie koloruje większość swoich danych wyjściowych, ale istnieje główny przełącznik, jeśli nie podoba Ci się to zachowanie. Aby wyłączyć wszystkie kolorowe wyjścia terminala Gita, wykonaj poniższe polecenie:

$ git config --global color.ui false

Domyślnym ustawieniem jest auto, które koloruje wyjście, gdy jest ono kierowane bezpośrednio do terminala, ale pomija kody sterujące związane z kolorami, gdy wyjście jest przekierowywane do potoku lub pliku.

Opcję tę można też ustawić ją na always, by ignorowała różnicę między terminalami a potokami. Rzadko będziesz tego chciał; w większości scenariuszy, jeśli chcesz mieć kody sterujące związane z kolorami na przekierowanym wyjściu, możesz zamiast tego przekazać flagę --color do komendy Git, aby wymusić ich użycie. Domyślne ustawienie jest prawie zawsze tym, czego będziesz potrzebował.

color.*

Jeżeli chciałbyś móc bardziej dokładnie ustalać co i w jaki sposób jest pokazywane w kolorze, Git dostarcza odpowiednie ustawienia. Każde z nich może mieć wartość true, false lub always:

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

Dodatkowo, każde z nich ma dodatkowe ustawienia, których możesz użyć, aby zmienić konkretne kolory dla części z wyświetlanego wyniku, jeżeli chciałbyś nadpisać jakiś z kolorów. Na przykład, aby pokazać w kolorze wynik komendy diff z niebieskim kolorem pierwszoplanowym, czarnym tłem i pogrubioną czcionką, uruchom:

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

Możesz ustawić kolor na jedną z wartość z podanego zbioru: normal, black, red, green, yellow, blue, magenta, cyan lub white. Jeżeli chciałbyś użyć dodatkowego atrybutu takiego jak pogrubienie z poprzedniego przykładu, możesz wykorzystać bold, dim, ul (z ang. underline, czyli podkreślenie), blink oraz reverse (zamiana koloru liter i tła).

Zewnętrzne narzędzia do łączenia i pokazywania różnic

Chociaż Git posiada wbudowaną obsługę narzędzia diff, którego dotychczas używałeś, możesz ustawić inny zewnętrzny program zamiast niego. Możesz również ustawić graficzny program pozwalający na łączenie zmian i rozwiązywanie konfliktów, bez konieczności robienia tego ręcznie. Zaprezentujemy na przykładzie Perforce Visual Merge Tool (P4Merge) w jaki sposób ustawić do obsługi łączenia i pokazywania różnic zewnętrzny program, ponieważ ma on prosty graficzny interfejs i jest darmowy.

Jeżeli chcesz tego również spróbować, P4Merge działa na wszystkich głównych platformach, więc prawdopodobnie będziesz mógł to zrobić. Będę używał nazw ścieżek w przykładach które działają na systemach Mac i Linux; dla systemu Windows będziesz musiał zmienić /usr/local/bin na odpowiednią ścieżkę w Twoim środowisku.

Aby rozpocząć, pobierz P4Merge z http://www.perforce.com/downloads/Perforce/. Następnie skonfigurujesz zewnętrzne skrypty, aby uruchamiały Twoje polecenia. Użyjemy ścieżki Mac dla pliku wykonywalnego; w innych systemach będzie to miejsce, gdzie zainstalowany jest binarny plik wykonywalny p4merge. Skonfiguruj skrypt o nazwie extMerge, który wywoła Twój program z wszystkimi podanymi argumentami:

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

Skrypt do obsługi diff sprawdza czy zostało podanych 7 argumentów i przekazuje dwa z nich do skryptu obsługującego merge. Domyślnie, Git przekazuje te argumenty do programu obsługującego pokazywanie różnic:

path old-file old-hex old-mode new-file new-hex new-mode
ścieżka stary-plik stara-wartość-hex stary-tryb nowy-plik nowa-wartość-hex nowy-tryb

Ponieważ potrzebujesz tylko argumentów stary-plik i nowy-plik, w skrypcie przekazujesz tylko te które potrzebujesz.

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

Musisz również upewnić się, że te narzędzia mają nadane prawa wykonywania:

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

Teraz możesz skonfigurować swój plik konfiguracyjny, aby użyć niestandardowych narzędzi do rozwiązywania łączenia i pokazywania różnic. Wymaga to kilku niestandardowych ustawień: merge.tool, aby powiedzieć Gitowi, jakiej strategii użyć, mergetool.<tool>.cmd, aby określić, jak uruchomić polecenie, mergetool.<tool>.trustExitCode, aby powiedzieć Gitowi, czy kod wyjścia tego programu wskazuje na udane rozwiązanie problemu łączenia, i diff.external, aby powiedzieć Gitowi, jakie polecenie uruchomić dla pokazywania różnic. Tak więc, możesz albo uruchomić cztery poniższe komendy konfiguracyjne:

$ 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

lub możesz zmienić swój plik ~/.gitconfig i dodać następujące linie:

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

Po wprowadzeniu tych ustawień, jeżeli uruchomisz komendę diff w poniższy sposób:

$ git diff 32d1776b1^ 32d1776b1

to zamiast otrzymania wyniku w wierszu poleceń, Git uruchomi program P4Merge, pokazując wynik podobny do poniższego:

P4Merge.
Figure 143. P4Merge.

Jeżeli spróbujesz połączyć dwie gałęzie, które zakończy się konfliktem, możesz uruchomić komendę git mergetool; zostanie uruchomiony skrypt P4Merge, pozwalający na rozwiązanie konfliktów poprzez interfejs graficzny GUI.

Zaletą tej konfiguracji jest to, że możesz zmienić łatwo zmienić narzędzia służące do porównywania (diff), oraz łączenia (merge). Na przykład, aby skrypty extDiff i extMerge uruchamiały KDiff3, musisz tylko zmienić plik extMerge:

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

Od teraz Git będzie używał programu KDiff3 podczas pokazywania różnic oraz rozwiązywania konfliktów.

Git jest wstępnie przygotowany na używanie wielu innych narzędzi do rozwiązywania scalania bez konieczności konfigurowania wiersza poleceń. Aby zobaczyć listę narzędzi, które obsługuje, wydaj poniższe polecenie:

$ 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.

Jeśli nie jesteś zainteresowany używaniem KDiff3 do pokazywania różnic, ale raczej chcesz go używać tylko do rozwiązywania łączenia, a polecenie kdiff3 jest w Twojej ścieżce, to możesz uruchomić:

$ git config --global merge.tool kdiff3

Jeśli uruchomisz to zamiast ustawiania plików extMerge i extDiff, Git użyje KDiff3 do rozwiązywania scalenia i normalnego narzędzia Git diff do wyświetlania różnic.

Formatowanie i białe znaki

Problemy związane z formatowaniem i białymi znakami są jednymi z bardziej uciążliwych i wyrafinowanych, które wielu deweloperów mogą spotkać podczas pracy, szczególnie jeżeli korzystają z różnych systemów operacyjnych. Bardzo łatwo można je wprowadzić w łatach lub modyfikacjach, poprzez samoistne dodanie ich przez edytor tekstowy, lub dodanie znaku powrotu karetki na końcach linii przez programistów korzystających z systemu Windows. Git posiada kilka opcji konfiguracyjnych, które pomagają rozwiązać te problemy.

core.autocrlf

Jeżeli programujesz na systemie Windows, lub używasz innego systemu, ale współpracujesz z osobami które programują na tym systemie, prawdopodobnie będziesz miał w pewnym momencie problemy związane ze znakami końca linii. Dzieje się tak dlatego, ponieważ w celu oznaczenia końca wiersza w swoich plikach system Windows używa dwóch znaków, tj. znaku powrotu karetki (CR) i znaku nowej linii (LF), a tymczasem w systemach Mac i Linux użwany jest jedynie znak nowej linii (LF). To jest subtelny, ale bardzo irytujący fakt przy współpracy na wielu platformach; wiele edytorów w Windows po cichu zastępuje istniejące zakończenia linii w stylu LF znakiem CRLF lub wstawia oba znaki kończące linię, gdy użytkownik naciśnie klawisz Enter.

Git może to obsłużyć poprzez automatyczną konwersję linii CRLF na LF, gdy wykonujesz commit, i odwrotnie podczas pobierania kodu na dysk. Możesz włączyć tą funkcjonalność za pomocą ustawienia core.autocrlf. Jeżeli pracujesz na systemie Windows, ustaw jej wartość na true – zamieni to znaki LF na CRLF podczas pobierania kodu:

$ git config --global core.autocrlf true

Jeżeli pracujesz na systemie Linux lub Mac, który używa znaków LF oznaczających koniec wiersza, nie będziesz chciał, aby Git automatycznie konwertował je podczas pobierania kodu; jednakże, jeżeli zostanie przez pomyłkę wgrany plik z zakończeniami CRLF, możesz chcieć aby Git je poprawił. Możesz wskazać Git, aby konwertował znaki CRLF na LF podczas commita, ale nie w odwrotną stronę ustawiając core.autocrlf na input:

$ git config --global core.autocrlf input

Takie ustawienia powinny zachować znaki CRLF na systemach Windows, a LF na systemach Mac i Linux oraz w repozytorium.

Jeżeli jesteś programistą tworzącym aplikację przeznaczoną wyłącznie na systemy Windows, możesz zupełnie wyłączyć tą funkcjonalność przez ustawienie wartości false, przez co znaki powrotu karetki również będą zapisywanie w repozytorium:

$ git config --global core.autocrlf false

core.whitespace

Git comes preset to detect and fix some whitespace issues. It can look for six primary whitespace issues – three are enabled by default and can be turned off, and three are disabled by default but can be activated.

The ones that are turned on by default are blank-at-eol, which looks for spaces at the end of a line; blank-at-eof, which notices blank lines at the end of a file; and space-before-tab, which looks for spaces before tabs at the beginning of a line.

The three that are disabled by default but can be turned on are indent-with-non-tab, which looks for lines that begin with spaces instead of tabs (and is controlled by the tabwidth option); tab-in-indent, which watches for tabs in the indentation portion of a line; and cr-at-eol, which tells Git that carriage returns at the end of lines are OK.

You can tell Git which of these you want enabled by setting core.whitespace to the values you want on or off, separated by commas. You can disable settings by either leaving them out of the setting string or prepending a - in front of the value. For example, if you want all but cr-at-eol to be set, you can do this:

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

Git will detect these issues when you run a git diff command and try to color them so you can possibly fix them before you commit. It will also use these values to help you when you apply patches with git apply. When you’re applying patches, you can ask Git to warn you if it’s applying patches with the specified whitespace issues:

$ git apply --whitespace=warn <patch>

Or you can have Git try to automatically fix the issue before applying the patch:

$ git apply --whitespace=fix <patch>

These options apply to the git rebase command as well. If you’ve committed whitespace issues but haven’t yet pushed upstream, you can run git rebase --whitespace=fix to have Git automatically fix whitespace issues as it’s rewriting the patches.

Server Configuration

Not nearly as many configuration options are available for the server side of Git, but there are a few interesting ones you may want to take note of.

receive.fsckObjects

Git is capable of making sure every object received during a push still matches its SHA-1 checksum and points to valid objects. However, it doesn’t do this by default; it’s a fairly expensive operation, and might slow down the operation, especially on large repositories or pushes. If you want Git to check object consistency on every push, you can force it to do so by setting receive.fsckObjects to true:

$ git config --system receive.fsckObjects true

Now, Git will check the integrity of your repository before each push is accepted to make sure faulty (or malicious) clients aren’t introducing corrupt data.

receive.denyNonFastForwards

If you rebase commits that you’ve already pushed and then try to push again, or otherwise try to push a commit to a remote branch that doesn’t contain the commit that the remote branch currently points to, you’ll be denied. This is generally good policy; but in the case of the rebase, you may determine that you know what you’re doing and can force-update the remote branch with a -f flag to your push command.

To tell Git to refuse force-pushes, set receive.denyNonFastForwards:

$ git config --system receive.denyNonFastForwards true

The other way you can do this is via server-side receive hooks, which we’ll cover in a bit. That approach lets you do more complex things like deny non-fast-forwards to a certain subset of users.

receive.denyDeletes

One of the workarounds to the denyNonFastForwards policy is for the user to delete the branch and then push it back up with the new reference. To avoid this, set receive.denyDeletes to true:

$ git config --system receive.denyDeletes true

This denies any deletion of branches or tags – no user can do it. To remove remote branches, you must remove the ref files from the server manually. There are also more interesting ways to do this on a per-user basis via ACLs, as you’ll learn in An Example Git-Enforced Policy.

scroll-to-top