Git
Chapters ▾ 2nd Edition

8.1 Git aanpassen - Git configuratie

Tot dusver hebben we de grondbeginselen behandeld van de werking van Git en hoe het te gebruiken, en we hebben een aantal instrumenten de revue laten passeren die Git je biedt om het eenvoudig en effectief te gebruiken. In dit hoofdstuk, zullen we laten zien hoe je Git op een meer aangepaste manier kan laten werken, door een aantal belangrijke configuratie settings te laten zien en het hooks systeem. Met deze gereedschapppen is het eenvoudig om Git te laten werken op de manier waarop jij, je bedrijf of je groep het nodig heeft.

Git configuratie

Zoals je al kort heb kunnen zien in Aan de slag, kan je Git configuratie settings aangeven met het git config commando. Een van de eerste dingen die je hebt gedaan was het inrichten van je naam en e-mail adres:

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

Nu gaan we je een aantal van de meer interessante opties laten zien die je op deze manier kunt instellen om jouw Git gebruik aan te passen.

Eerst, een korte terugblik: Git gebruikt een reeks van configuratie bestanden om te bepalen welke niet standaard gedragingen je hebt aangevraagd. De eerste plek waar Git naar kijkt voor deze waarden is in een /etc/gitconfig bestand, welke de waarden bevat voor elke gebruiker op het systeem en al hun repositories. Als je de optie --system doorgeeft aan git config, leest en schrijft deze naar dit specifieke bestand.

De volgende plaats waar Git kijkt is het`~/.gitconfig` (of ~/.config/git/config) bestand, die voor elke gebruiker anders kan zijn. Je kunt Git naar dit bestand laten lezen en schrijven door de --global optie door te geven.

Als laatste kijkt Git naar configuratie waarden in het configuratie bestand in de Git directory (.git/config) van de repository die je op dat moment gebruikt. Deze waarden zijn gebonden aan alleen die ene repository.

Elk van deze “levels” (systeem, globaal, lokaal) overschrijft de waarden van de vorige, dus waarden in ` .git/config` overtroeven die in /etc/gitconfig bijvoorbeeld.

Note

De configuratie bestanden van Git zijn gewone tekstbestanden, dus je kunt deze waarden ook aanpassen door het bestand handmatig te bewerken en de juiste syntax te gebruiken. Het is echter over het algemeen eenvoudiger om het git config commando te gebruiken.

Basis werkstation configuratie

De configuratie opties die door Git worden herkend vallen uiteen in twee categoriën: de kant van het werkstation en die van de server. De meerderheid van de opties zitten aan de kant van het werkstation - welke jouw persoonlijke voorkeuren voor de werking inrichten. Er worden heel, heel erg veel configuratie opties ondersteund, maar een groot gedeelte van deze zijn alleen nuttig in bepaalde uitzonderingsgevallen. We zullen alleen de meest voorkomende en nuttigste hier behandelen. Als je een lijst wilt zien van alle opties die jouw versie van Git ondersteunt, kan je dit aanroepen:

$ man git-config

Dit commando geeft je een lijst van alle beschikbare opties met nogal wat detail informatie. Je kunt deze referentie materiaal ook vinden op http://git-scm.com/docs/git-config.html.

core.editor

Standaard gebruikt Git hetgeen je hebt ingesteld als je standaard tekstverwerker ($VISUAL of $EDITOR) en anders valt het terug op de vi tekstverwerker om jouw commit en tag berichten te maken en te onderhouden. Om deze standaard naar iets anders te verandereen, kan je de core.editor instelling gebruiken:

$ git config --global core.editor emacs

Nu maakt het niet meer uit wat je standaard shell editor is, Git zal Emacs opstarten om je berichten te wijzigen.

commit.template

Als je dit instelt op het pad van een bestand op je systeem, zal Git dat bestand gebruiken als het standaard bericht als je commit. Bijvoorbeeld, stel dat je een sjabloon bestand op ~/.gitmessage.txt hebt gemaakt dat er zo uitziet:

subject line

what happened

[ticket: X]

Om Git te vertellen dat het dit als het standaard bericht moet gebruiken dat in je tekstverwerker verschijnt als je git commit aanroept, zet dan de commit.template configuratie waarde:

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

Dan zal je tekstverwerker het volgende als je commit bericht sjabloon gebruiken als je gaat committen:

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

Als je team een commit-bericht voorschrift heeft, dan zal het inrichten van een sjabloon voor dat voorschrift op jouw systeem en het inrichten van Git om dit standaard te gebruiken helpen met het vergroten van de kans dat dat voorschrift ook daadwerkelijk wordt opgevolgd.

core.pager

Het instellen van deze waarde bepaalt welke pagineerhulp wordt gebruikt als Git uitvoer als log en diff gaat pagineren. Je kunt dit op more of jouw favoriete pagineerhulp instellen (standaard is het less), of je kunt het uitzetten door een lege waarde te geven:

$ git config --global core.pager ''

Als je dat aanroept, zal Git de gehele uitvoer van alle commando’s tonen, onafhankelijk van de lengte van deze uitvoer.

user.signingkey

Als je getekende geannoteerde tags aanmaakt (zoals behandeld in Je werk tekenen), zal het inrichten van je GPG handtekening als configuratie setting dingen eenvoudiger maken. Stel jouw sleutel ID als volgt in:

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

Nu kan je tags tekenen zonder elke keer je sleutel op te hoeven geven als je het git tag commando aanroept:

$ git tag -s <tag-name>

core.excludesfile

Je kunt patronen in het .gitignore bestand van je project zetten om Git deze niet als untracked bestanden te laten beschouwen of deze zal proberen te stagen als je git add op ze aanroept, zoals beschreven in Bestanden negeren.

Maar soms wil je bepaalde bestanden negeren voor alle repositories waar je in werkt. Als je computer onder Mac OS X draait, ben je waarschijnlijk bekend met .DS_Store bestanden. Als je voorkeurs-tekstverwerker Emacs of Vim is, zullen bestanden die eindigen op een ~ je bekend voorkomen.

Deze instelling laat je een soort globale .gitingore bestand aanmaken. Als je een ~/.gitignore_global bestand aanmaakt met deze inhoud:

*~
.DS_Store

…​en je roept git config --global core.excludesfile ~/.gitignore_global aan, zal Git je nooit meer lastig vallen voor deze bestanden.

help.autocorrect

Als je een typefout maakt in een commando, laat het je iets als dit zien:

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

Did you mean this?
    checkout

Git probeert behulpzaam uit te vinden wat je bedoelt kunt hebben, maar weigert het wel dit uit te voeren. Als je help.autocorrect op 1 instelt, zal Git het commando daadwerkelijk voor je uitvoeren:

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

Merk het “0.1 seconden” gedoe op. help.autocorrect is eigenlijk een integer waarde die tienden van een seconde vertegenwoordigt. Dus als je het op 50 zet, zal Git je 5 seconden geven om van gedachten te veranderen voordat het automatisch gecorrigeerde commando wordt uitgevoerd.

Kleuren in Git

Git ondersteunt gekleurde terminal uitvoer volledig, wat enorm helpt in het snel en eenvoudig visueel verwerken van de uitvoer van commando’s. Een aantal opties kunnen je helpen met het bepalen van jouw voorkeurs-kleuren.

color.ui

Git geeft automatisch de meeste van haar uitvoer in kleur weer, maar er is een hoofdschakelaar als dit gedrag je niet bevalt. Om alle kleuren uitvoer van Git uit te zetten, voer je dit uit:

$ git config --global color.ui false

De standaard waarde is auto, wat de uitvoer kleur geeft als het direct naar een terminal wordt gestuurd, maar laat de kleuren-stuurcodes achterwege als de uitvoer naar een pipe of een bestand wordt omgeleid.

Je kunt het ook instellen op always om het onderscheid tussen terminals en pipes te negeren. Je zult dit zelden willen in de meeste gevallen, als je kleuren-stuurcodes in je omgeleide uitvoer wilt, kan je in plaats daarvan een --color vlag aan het Git commando doorgeven om het te dwingen om kleurcodes te gebruiken. De standaard instelling is vrijwel altijd hetgeen je zult willen.

color.*

Als je meer controle wilt hebben over welke commando’s gekleurd worden en hoe, heeft Git argument-specifieke kleuren-instellingen. Elk van deze kan worden gezet op true, false of always:

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

Daarenboven heeft elk van deze specifiekere instellingen die je kunt gebruiken om specifieke kleuren voor delen van de uitvoer te bepalen, als je elke kleur zou willen herbepalen. Bijvoorbeeld, om de meta-informatie in je diff uitvoer op een blauwe voorgrond, zwarte achtergrond en vetgedrukte tekst in te stellen, kan je het volgende uitvoeren:

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

Je kunt de kleur instellen op elk van de volgende waarden: normal, black, red, green, yellow, blue, magenta, cyan, of white. Als je een attribuut als vetgedrukt (bold) in het vorige voorbeeld wilt, kan je kiezen uit bold, dim (minder helder), ul (onderstrepen, underline), blink (knipperen), en reverse (verwissel voor- en achtergrond).

Externe merge en diff tools

Hoewel Git een interne implementatie van diff heeft, wat hetgeen is wat we hebben laten zien in dit boek, kan je een externe tool inrichten. Je kunt ook een grafische merge-conflict-oplosgereedschap inrichten in plaats van het handmatig oplossen van de conflicten. We zullen je het inrichten van het Perforce Visual Merge Tool (P4Merge) laten zien om je diffs en merge resoluties te laten doen, omdat het een fijne grafische tool is en omdat het is gratis.

Als je dit wilt proberen, P4Merge werkt op alle meest gebruikte platformen, dus je zou het op deze manier moeten kunnen doen. We zullen in de voorbeelden pad-namen gaan gebruiken die op Mac en Linux systemen werken; voor Windows zal je /usr/local/bin in een uitvoerbaar pad moeten veranderen in jouw omgeving.

Om te beginnen, download P4Merge van http://www.perforce.com/downloads/Perforce/. Vervolgens ga je externe wrapper scripts maken om je commando’s uit te voeren. We zullen het Mac pad voor de executable gebruiken; op andere systemen zal het zijn waar je het p4merge binary bestand hebt geïnstalleerd. Maak een merge wrapper script genaamd extMerge dat je binary aanroept met alle gegeven argumenten:

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

De diff wrapper verifiëert dat er zeven argumenten worden doorgegeven en geeft twee ervan door aan je merge script. Standaard geeft Git de volgende argumenten door aan het diff programma:

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

Omdat je alleen de old-file en new-file argumenten wilt, gebruik je het wrapper script om degene door te geven die je nodig hebt.

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

Je moet ook ervoor zorgen dat deze scripts uitvoerbaar worden gemaakt:

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

Nu kan je jouw configuratie bestand inrichten om jouw aangepaste merge oplossing en diff instrumenten worden gebruikt. Dit vergt een aantal aangepaste instellingen: merge.tool om Git te vetellen welke strategie er gebruikt dient te worden, mergetool.<tool>.cmd om aan te geven hoe het commando aan te roepen, mergetool.<tool>.trustExitCode om Git te vertellen of de uitvoercode van dat programma een succesvolle merge oplossing aangeeft of niet, en diff.external om Git te vertellen welk commando het moet aanroepen voor diffs. Dus je kunt kiezen om vier config commando’s aan te roepen

$ 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

of je kunt je ~/.gitconfig bestand aanpassen door deze regels toe te voegen:

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

Als dit ingericht is, zal, als je diff commando’s als deze aanroept:

$ git diff 32d1776b1^ 32d1776b1

Git, in plaats van de diff uitvoer op de commando-regel te geven, P4Merge opstarten wat er ongeveer zo uit zal zien:

P4Merge.
Figure 143. P4Merge.

Als je probeert om twee branches te mergen en je krijgt vervolgens merge conflicten, kan je het commando git mergetool aanroepen; Git zal P4Merge opstarten om je de conflicten middels dat grafische gereedschap op te laten lossen.

Het mooie van deze wrapper inrichting is dat je je diff en merge gereedschappen eenvoudig kan wijzigen. Bijvoorbeeld, om je extDiff en extMerge gereedschappen te wijzigen om het KDiff3 gereedschap aan te roepen, is het enige wat je hoeft te doen het wijzigen van je extMerge bestand:

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

Nu zal Git het KDiff3 gereedschap gebruiken voor het bekijken van diffs en het oplossen van merge conflicten.

Git is voor-ingericht om een aantal andere merge-oplossings gereedschappen te gebruiken waarbij er geen noodzaak is om de cmd-configuratie op te zetten. Om een lijst te zien van de ondersteunde gereedschappen, probeer eens dit:

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

Als je niet geïntereseerd bent in het gebruik van KDiff3 voor diff, maar dit liever wilt gebruiken voor alleen het oplossen van merge conflicten, en het kdiff3 commando is op je pad, dan kan je dit aanroepen:

$ git config --global merge.tool kdiff3

Als je dit uitvoert in plaats van de extMerge en extDiff bestanden te maken, zal Git KDiff3 gebruiken voor merge conflict oplossingen en het reguliere Git diff gereedschap voor diffs.

Formatering en witruimtes

Formatering en witruimte problemen zijn een paar van de meest frustrerende en subtiele problemen die veel ontwikkelaars tegenkomen wanneer ze samenwerken, vooral bij verschillende platforms. Het is erg eenvoudig om middels patches of ander gedeeld werk om subtiele witruimte wijzigingen te introduceren omdat tekstverwerkers deze stilletjes invoeren, en als je bestanden ooit in aanraking komen met een Windows systeem, zullen de regeleinden mogelijk vervangen zijn. Git heeft een aantal configuratie opties om je bij deze problemen te helpen.

core.autocrlf

Als je in Windows programmeert en werkt met mensen die dat niet doen (of vice-versa), zal je waarschijnlijk op enig moment met regel-einde problematiek te maken krijgen. Dit is omdat Windows zowel een wagen-terugvoer teken (carriage-return) en een regelopvoer teken (linefeed) gebruikt voor nieuwe regels in haar bestanden, waar Mac en Linux systemen alleen het linefeed teken gebruiken. Dit is een subtiel maar ongelofelijk ergerlijk feit van het werken op verschillende platforms; veel tekstverwerkers op Windows vervangen stilletjes bestaande LF-stijl regeleinden met CRLF, of voegen beide regel-einde karakters in als de gebruiker de enter toets gebruikt.

Git kan dit verwerken door automatisch CRLF regel-einden te converteren in een LF als je een bestand in de index toevoegt, en vice-versa als je code uitcheckt naar je bestandssysteem. Je kunt deze functionaliteit aanzetten met de core.autocrlf instelling. Als je op een Windows machine werkt, zet dit dan op true - dit zal LF einden naar CRLF vertalen als je code uitcheckt:

$ git config --global core.autocrlf true

Als je op een Linux of Mac systeem werkt die LF regeleinden gebruikt, dan wil je niet dat Git deze automatisch vertaalt als je bestanden uitcheckt, echter als een bestand met CRLF regeleinden per ongeluk binnenkomt, dan zou je wellicht willen dat Git dit rechttrekt. Je kunt Git vertellen om CRLF naar LF te vertalen bij een commit, maar niet omgekeerd door de instelling core.autocrlf op input te zetten:

$ git config --global core.autocrlf input

Met deze instelling zou je uit moeten komen met CRLF regeleinden in Windows checkouts, maar LF regeleinden op Mac en Linux systemen en in de repository.

Als je een Windows programmeur bent die aan een project werkt voor alleen Windows, kan je deze functionaliteit uitzetten, waarbij carriage returns in de repository worden vastgelegd door de configuratie waarde op false te zetten:

$ git config --global core.autocrlf false

core.whitespace

Git wordt geleverd met de instelling om een aantal witruimte problemen te detecteeren en op te lossen. Het kan zoeken naar zes meestvoorkomende witruimte problemen - drie ervan zijn standaard ingeschakeld en kunnen worden uitgeschakeld, en drie zijn uitgeschakeld maar kunnen worden geactiveerd.

Degenen die standaard aanstaan zin blank-at-eol, die naar spaties aan het eind van een regel kijkt; blank-at-eof, die blanko regels opmerkt aan het eind van een bestand; en space-before-tab, die kijkt naar spaties voor tabs aan het begin van een regel.

De drie die standaard uitstaan, maar die kunnen worden aangezet, zijn indent-with-non-tab, die kijkt naar regels die beginnen met spaties in plaats van tabs (en wordt geregels met de tabwidth optie); tab-in-indent, die kijkt naar tabs in het inspring-gedeelte van een regel; en cr-at-eol, welke Git vertelt dat carriage returns aan het eind van regels worden geaccepteerd.

Je kunt Git vertellen welke van deze je ingeschakeld wilt hebben door core.whitespace op de waarden te zetten die je aan of uit wilt hebben, gescheiden met komma’s. Je kunt instellingen uitzetten door ze weg te laten uit de instelling-reeks of ze vooraf te laten gaan met een -. Bijvoorbeeld, als je alles behalve cr-at-eol wilt inschakelen kan je dit doen:

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

Git zal deze problemen opsporen als je een git diff commando aanroept en ze proberen met een kleur aan te geven zodat je ze mogelijk kunt oplossen voordat je commit. Het zal deze waarden ook gebruiken om je te helpen als je patches toepast met git apply. Als je patches aan het toepassen bent, kan je Git ook vragen om je te waarschuwen als het patches toepast met de aangegeven witruimte problematiek:

$ git apply --whitespace=warn <patch>

Of je kunt Git het probleem automatisch laten proberen op te lossen voordat het de patch toepast:

$ git apply --whitespace=fix <patch>

Deze opties zijn ook van toepassing voor het git rebase commando. Als je witruimte problemen hebt gecommit, maar je hebt ze nog niet stroomopwaarts gepushed, kan je git rebase --whitespace=fix aanroepen om Git deze problemen automatisch te laten oplossen als het de patches herschrijft.

Server configuratie

Er zijn lang niet zoveel configuratie opties beschikbaar voor de server kant van Git, maar er zijn een aantal interessante waar je wellicht naar wilt kijken.

receive.fsckObjects

Git is in staat om te verifiëren dat elk ontvangen object bij een push nog steeds een passende SHA-1 checksum heeft en naar geldige objecten wijst. Dit doet het echte niet standaard; het is een relatief dure operatie, en kan het uitvoeren van de operatie vertragen, zeker bij grote repositories of pushes. Als je wilt dat Git object consistentie bij elke push controleert, kan je dit afdwingen door receive.fsckObjects op true te zetten:

$ git config --system receive.fsckObjects true

Nu zal Git de integriteit van je repository controleren voordat elke push wordt geaccepteerd om er zeker van te zijn dat defecte (of kwaadwillende) werkstations geen corrupte gegevens aanleveren.

receive.denyNonFastForwards

Als je commits rebased die je al gepushed hebt en dan weer probeert te pushen, of op een andere manier probeert een commit te pushen naar een remote branch die de commit niet bevat waar de remote branch op dit moment naar wijst, zal dit geweigerd worden. Dit is normaalgesproken een goed beleid, maar in het geval van de rebase, kan je besluiten dat je weet wat je aan het doen bent en de remote branch geforceerd updaten met een -f vlag bij je push commando.

Om Git te vertellen om geforceerd pushen te weigeren, zet je receive.denyNonFastForwards:

$ git config --system receive.denyNonFastForwards true

De andere manier waarop je dit kunt doen is via receive hooks aan de kant van de server, waar we straks meer over gaan vertellen. Die aanpak stelt je ook in staat om iets complexere dingen te doen als het weigeren van non-fast-forwards bij een bepaalde groep van gebruikers.

receive.denyDeletes

Een van de manieren om om het denyNonFastForwards beleid heen te werken is om als gebruiker de branch te verwijderen en deze dan weer te pushen met de nieuwe referenties. Om dit te voorkomen, zet receive.denyDeletes op true:

$ git config --system receive.denyDeletes true

Dit weigert het verwijderen van branches of tags - geen enkele gebruiker kan dit doen. Om remote branches te verwijderen, moet je de ref-bestanden handmatig van de server verwijderen. Er zijn nog meer interessante manieren om dit te doen op een gebruikersgerichte manier via ACL’s, zoals je zult zien in Een voorbeeld van Git-afgedwongen beleid.