This is an in-progress translation.
To help translate the book, please fork the book at GitHub and push your contributions.

Projectonderhoud

Naast weten hoe effectief bij te dragen aan een project, moet je waarschijnlijk ook weten hoe je deze onderhoud. Dit kan bestaan uit het accepteren en toepassen van patches gegenereerd via ‘format-patch’ die naar jou gemaild zijn, of het integreren van veranderingen in de remote branches voor repositories die je hebt toegevoegd als remotes aan je project. Of je nu een canonieke repository onderhoud, of wilt bijdragen door het controleren of goedkeuren van patches, je moet weten hoe werk te aanvaarden op een manier die het duidelijkst is voor andere medewerkers en duurzaam door jou op de lange termijn.

Werken in onderwerp branches

Als je overweegt om nieuw werk te integreren, is het normaliter een goed idee om het uit te proberen in een onderwerp branch – een tijdelijke branch, speciaal gemaakt om dat nieuwe werk te proberen. Op deze manier is het handig om een patch individueel af te stemmen en het weg te laten als het niet werkt, totdat je tijd hebt om er op terug te komen. Als je een eenvoudige branchnaam maakt, gebaseerd op het thema van het werk dat je gaat proberen, bijvoorbeeld ruby_client of zoiets beschrijvends, dan kun je het makkelijk onthouden als je het voor een tijdje moet achterlaten en er later op terug moet komen. De beheerder van het Git project heeft de neiging om deze branches ook van een naamruimte te voorzien – zoals sc/ruby_client, waarbij sc een afkorting is van de persoon die het werk heeft bijgedragen. Zoals je je zult herinneren, kun je de branch gebaseerd op je master branch zo maken:

$ git branch sc/ruby_client master

Of, als je er ook meteen naar wilt omschakelen, kun je de checkout -b optie gebruiken:

$ git checkout -b sc/ruby_client master

Nu ben je klaar om je bijgedragen werk in deze onderwerp branch toe te voegen, en te bepalen of je het wilt samenvoegen in je lange termijn branches.

Patches uit e-mail toepassen

Als je een patch per e-mail ontvangt, die je moet integreren in je project, moet je de patch in je onderwerp branch toepassen om het te evalueren. Er zijn twee manieren om een ge-emailde patch toe te passen: met git apply of met git am.

Een patch toepassen met apply

Als je de patch ontvangen hebt van iemand die het gegenereerd heeft met de git diff of een Unix diff commando, kun je het toepassen met het git apply commando. Aangenomen dat je de patch als /tmp/patch-ruby-client.patch opgeslagen hebt, kun je de patch als volgt toepassen:

$ git apply /tmp/patch-ruby-client.patch

Dit wijzigt de bestanden in je werkmap. Het is vrijwel gelijk aan het uitvoeren van een patch -p1 commando om de patch toe te passen, alhoewel het meer paranoïde is en minder wazige paren dan patch. Het handelt ook bestandstoevoegingen af, verwijderingen, en hernoemingen als ze beschreven staan in het git diff formaat, wat patch niet doet. Als laatste is git apply een “pas alles toe of laat alles weg” model, waarbij alles of niets wordt toegepast, waarbij patch gedeeltelijke patches kan toepassen, zodat je werkmap in een vreemde status achterblijft. git apply is over het algemeen meer paranoïde dan patch. Het zal geen commit voor je aanmaken – na het uitgevoerd te hebben, moet je de geïntroduceerde wijzigingen handmatig stagen en committen.

Je kunt ook git apply gebruiken om te zien of een patch netjes toepast, voordat je het echt toepast – je kunt git apply --check uitvoeren met de patch:

$ git apply --check 0001-seeing-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply

Als er geen uitvoer is, dan zou de patch netjes toe moeten passen. Dit commando eindigt ook met een status niet gelijk aan nul als de controle faalt, zodat je het kunt gebruiken in scripts als je dat wilt.

Een patch met am toepassen

Als de bijdrager een Git gebruiker is en zo goed was om het format-patch commando te gebruiken om hun patch te genereren, dan is je werk eenvoudiger omdat de patch auteur informatie en een commit bericht voor je bevat. Als je kunt, moedig je bijdragers aan om format-patch te gebruiken in plaats van diff om patches te genereren voor je. Je zou alleen git apply hoeven te gebruiken voor oude patches en dat soort dingen.

Om een patch gegenereerd met format-patch toe te passen, gebruik je git am. Technisch is git am gemaakt om een mbox bestand te lezen, dat een eenvoudig gewone tekst formaat of is om één of meer e-mail berichten in een tekst bestand op te slaan. Het ziet er zoiets als dit uit:

From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

Dit is het begin van de uitvoer van het format-patch commando dat je gezien hebt in het vorige gedeelte. Dit is ook een geldig mbox e-mail formaat. Als iemand jou de patch goed gemaild heeft door gebruik te maken van git send-email, en je download dat in een mbox formaat, dan kun je git am naar dat mbox bestand wijzen, en het zal beginnen met alle patches die het ziet toe te passen. Als je een mail client uitvoert die meerdere e-mails kan opslaan in mbox formaat, dan kun je hele patch series in een bestand opslaan en dan git am gebruiken om ze stuk voor stuk toe te passen.

Maar, als iemand een patch bestand heeft ge-upload die gegenereerd is met format-patch naar een ticket systeem of zoiets, kun je het bestand lokaal opslaan en dan dat bestand dat bewaard is op je schijf aan git am geven om het toe te passen:

$ git am 0001-limit-log-function.patch
Applying: add limit to log function

Je kunt zien dat het netjes is toegepast, en automatisch een nieuwe commit voor je heeft aangemaakt. De auteur informatie wordt gehaald uit het From en Date veld in de kop, en het bericht van de commit wordt gehaald uit de Subject en inhoud (voor de patch van de e-mail. Bijvoorbeeld, als deze patch was toegepast van het mbox voorbeeld dat ik zojuist getoond heb, dan zou de gegenereerde commit er ongeveer zo uit zien:

$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author:     Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit:     Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700

   add limit to log function

   Limit log functionality to the first 20

De Commit informatie laat de persoon die de patch toepaste en de tijd waarop het was toegepast zien. De Author informatie is het individueel die de patch origineel gemaakt heeft en wanneer het origineel gemaakt is.

Maar, het is mogelijk dat de patch niet netjes toepast. Misschien is je hoofdbranch te ver afgeweken van de branch waarop de patch gebouwd is, of hangt de patch van een andere patch af, die je nog niet hebt toegepast. In dat geval zal het git am proces falen en je vragen wat je wilt doen:

$ git am 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".

Dit commando stopt conflict markeringen in alle bestanden waar het problemen mee heeft, net zoals een conflicterende samenvoeging of rebase operatie. Je lost dit probleem in een vergelijkbare manier op – wijzig het bestand om het conflict op te lossen, stage het bestand, en voer dan git am --resolved uit om door te gaan met de volgende patch:

$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: seeing if this helps the gem

Als je wil dat Git een beetje meer intelligent probeert om het conflict op te lossen, kun je een -3 optie eraan meegeven, wat zorgt dat Git een drieweg samenvoeging probeert. Deze optie staat standaard niet aan, omdat het niet werkt als de commit waarvan de patch zegt dat het op gebaseerd is niet in je repository zit. Als je die commit wel hebt – als de patch gebaseerd was op een publieke commit – dan is de -3 over het algemeen veel slimmer in het toepassen van een conflicterende patch:

$ git am -3 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.

In dit geval, probeerde ik een patch toe te passen die ik reeds toegepast had. Zonder de -3 optie ziet het eruit als een conflict.

Als je een aantal patches van een mbox toepast, kun je ook het am commando in een interactieve modus uitvoeren, wat bij iedere patch die het vind stopt en je vraagt of je het wilt toepassen:

$ git am -3 -i mbox
Commit Body is:
--------------------------
seeing if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all

Dit is fijn als je een aantal patches bewaard hebt, omdat je de patch eerst kunt zien als je je niet kunt herinneren wat het is, of de patch niet wilt toepassen als je het al gedaan hebt.

Als alle patches voor je onderwerp branch zijn toegepast en gecommit zijn op je branch, kun je kiezen of en hoe ze te integreren in een langer lopende branch.

Remote branches bekijken

Als je bijdrage van een Git gebruiker komt, die zijn eigen repository ingesteld heeft, een aantal patches daarin teruggezet heeft, en jou de URL naar de repository gestuurd heeft en de naam van de remote branch waarin de wijzigingen zitten, dan kun je ze toevoegen als een remote en de samenvoegingen lokaal doen.

Bijvoorbeeld, als Jessica je een e-mail stuurt waarin staat dat ze een mooie nieuw eigenschap in de ruby-client branch van haar repository heeft, kun je het testen door de remote toe te voegen en die branch lokaal te bekijken:

$ git remote add jessica git://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client

Als ze je later opnieuw e-mailt met een andere branch die een andere mooie eigenschap bevat, dan kun je die ophalen en bekijken omdat je de remote al ingesteld hebt.

Dit is erg handig als je consistent met een persoon werkt. Als iemand een enkele patch eens in de zoveel tijd bij te dragen heeft, dan is het accepteren per e-mail misschien minder tijdrovend dan eisen dat iedereen hun eigen server moet draaien en doorlopend remotes toevoegen en verwijderen om een paar patches te krijgen. Je zult waarschijnlijk ook honderden remotes hebben, elk voor iemand die maar een patch of twee bijdraagt. Maar, scripts en gehoste diensten maken dit misschien makkelijker – het hangt veel af van hoe jij ontwikkeld en hoe je bijdragers ontwikkelen.

Het andere voordeel van deze aanpak is dat je de historie van de commits ook krijgt. Alhoewel je misschien geldige samenvoeg problemen hebt, weet je waar in je historie hun werk is gebaseerd; een goede drieweg samenvoeging is de standaard in plaats van een -3 te moeten meegeven en hopen dat de patch gegenereerd was van een publieke commit waar je toegang toe hebt.

Als je niet consistent met een persoon werkt, maar toch op deze manier van hen wilt ophalen, dan kun je de URL van het remote repository geven aan het git pull commando. Dit haalt eenmalig op en bewaart de URL niet als een remote referentie:

$ git pull git://github.com/onetimeguy/project.git
From git://github.com/onetimeguy/project
 * branch            HEAD       -> FETCH_HEAD
Merge made by recursive.

Bepalen wat geïntroduceerd wordt

Nu heb je een onderwerp branch dat bijgedragen werk bevat. Op dit punt kun je bepalen wat je er mee wilt doen. Deze sectie bezoekt een paar commando’s opnieuw zodat je kunt zien hoe je ze kunt gebruiken om precies te reviewen wat je zult introduceren als je dit samenvoegt in je hoofd branch.

Het is vaak behulpzaam om een review te krijgen van alle commits die in deze branch zitten, maar die niet in je master branch zitten. Je kunt commits weglaten in de master branch door de --not optie mee te geven voor de branch naam. Bijvoorbeeld, als je bijdrager je twee patches stuurt en je wil een branch genaamd contrib maken en die patches daar toepassen, dan kun je dit uitvoeren:

$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Oct 24 09:53:59 2008 -0700

    seeing if this helps the gem

commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date:   Mon Oct 22 19:38:36 2008 -0700

    updated the gemspec to hopefully work better

Om te zien welke wijzigingen iedere commit introduceert, onthoud dan dat je de -p optie kunt meegeven aan git log en dan zal het de diff geïntroduceerd bij iedere commit weergeven.

Om een volledige diff te zien van wat zou gebeuren als je deze onderwerp branch samenvoegt met een andere branch, zul je misschien een vreemde truc moeten toepassen om de juiste resultaten te krijgen. Je zult misschien denken om dit uit te voeren:

$ git diff master

Dit commando geeft je een diff, maar het zou misleidend kunnen zijn. Als je master branch vooruit geschoven is sinds je de onderwerp branch er vanaf hebt gebaseerd, dan zul je ogenschijnlijk vreemde resultaten krijgen. Bijvoorbeeld, als je een regel in een bestand hebt toegevoegd op de master branch, dan zal een directe vergelijking van de snapshots eruit zien alsof de onderwerp branch die regel gaat verwijderen.

Als master een directe afstammeling is van je onderwerp branch, is dit geen probleem; maar als de twee histories uit elkaar zijn gegaan, zal de diff eruit zien alsof je alle nieuwe spullen in je onderwerp branch toevoegt en al het unieke weghaalt in de master branch.

Wat je echt wil zien zijn de wijzigingen die in de onderwerp branch zijn toegevoegd – het werk dat je zult introduceren als je deze branch met master samenvoegt. Je doet dat door Git de laatste commit op je onderwerp branch te laten vergelijken met de eerste gezamenlijke voorouder die het heeft met de master branch.

Technisch, kun je dat doen door de gezamenlijke voorouder expliciet uit te zoeken en dan daar je diff op uit te voeren:

$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db

Maar, dat is niet handig, dus levert Git een andere korte manier om hetzelfde te doen: de driedubbele punt syntax. In de context van het diff commando, kun je drie punten achter een andere branch zetten, om een diff te doen tussen de laatste commit van de branch waar je op zit en zijn gezamenlijke voorouder met een andere branch:

$ git diff master...contrib

Dit commando toont je alleen het werk dat je huidige onderwerp branch heeft geïntroduceerd sinds zijn gezamenlijke voorouder met master. Dat is een erg handige syntax om te onthouden.

Bijgedragen werk integreren

Als al het werk in je onderwerp branch klaar is om te worden geïntegreerd in een meer hoofdlijn branch, dan is de vraag hoe het te doen. En daarna, welke algemene werkwijze wil je gebruiken om je project te onderhouden? Je hebt een aantal keuzes, dus ik zal er een paar behandelen.

Samenvoeg werkwijzen

Een eenvoudige werkwijze voegt je werk in je master branch. In dit scenario, heb je een master branch die in feite stabiele code bevat. Als je werk in een onderwerp branch hebt dat jij gedaan hebt, of dat iemand anders heeft bijgedragen en jij hebt nagekeken, dan voeg je het in je master branch, verwijderd de onderwerp branch en vervolgt het proces. Als we een repository hebben met werk in twee branches genaamd ruby_client en php_client, dat eruit ziet zoals Figuur 5-19 en voegen ruby_client eerst in en vervolgens php_client, dan zal je historie er uit gaan zien zoals in Figuur 5-20.


Figuur 5-19. Historie met een aantal onderwerp branches.


Figuur 5-20. Na het samenvoegen van een onderwerp branch.

Dat is waarschijnlijk de eenvoudigste werkwijze, maar het is problematisch als je werkt met grotere repositories of projecten.

Als je meer ontwikkelaars hebt, of een groter project, dan zul je waarschijnlijk een minstens twee fasen samenvoeg cyclus willen gebruiken. In dit scenario, heb je twee langlopende branches, master en develop, waarin je bepaald dat master alleen vernieuwd wordt als een zeer stabiele vrijgave gedaan wordt en alle nieuwe code geïntegreerd is in de develop branch. Je zet beide branches regelmatig terug naar het publieke repository. Iedere keer als je een nieuw onderwerp branch hebt om samen te voegen (Figuur 5-21), voeg je het in develop (Figuur 5-22); daarna, als je een tag maakt van een vrijgave, dan doe je een fast-forward van master naar waar de nu stabiele develop branch is (Figuur 5-23).


Figuur 5-21. Voor een samenvoeging van een onderwerp branch.


Figuur 5-22. Na een samenvoeging van een onderwerp branch.


Figuur 5-23. Na een vrijgave van een onderwerp branch.

Als mensen het repository van je project op deze manier clonen, dan kunnen ze of master uit checken om de laatste stabiele versie te bouwen en die eenvoudig te kunnen bijhouden of ze kunnen develop uit checken, wat het nieuwere spul bevat. Je kunt dit concept ook doortrekken, waarbij je een integratie branch hebt waar al het werk samengevoegd wordt. Als de codebasis op die branch stabiel is en voor de testen slaagt, dan voeg je het in een develop branch; en als dat zichzelf een poosje stabiel heeft bewezen, dan fast-forward je je master branch.

Werkwijzen met grote samenvoegingen

Het Git project heeft vier langlopende branches: master, next, en pu (proposed updates, voorgestelde vernieuwingen), en maint voor onderhoudswerk. Als nieuw werk wordt geïntroduceerd door bijdragers, wordt het samengeraapt in onderwerp branches in het repository van de beheerder op een manier gelijk aan wat ik omschreven heb (zie Figuur 5-24). Op dit punt, worden de onderwerpen geëvalueerd om te bepalen of ze veilig zijn en klaar voor consumptie of dat ze nog wat werk nodig hebben. Als ze veilig zijn, worden ze in next samengevoegd, en wordt die branch teruggezet zodat iedereen de onderwerpen geïntegreerd kan proberen.


Figuur 5-24. Een complexe serie van parallelle bijgedragen onderwerp branches beheren.

Als de onderwerpen nog werk nodig hebben, dan worden ze in plaats daarvan samengevoegd in pu. Als bepaald wordt dat ze helemaal stabiel zijn, dan worden de onderwerpen opnieuw samengevoegd in master en worden dan herbouwd van de onderwerpen die in next waren, maar nog niet geslaagd waren voor master. Dit betekend dat master vrijwel altijd vooruit beweegt, next eens in de zoveel tijd gerebased wordt, en pu nog vaker gerebased wordt (zie Figuur 5-25).


Figuur 5-25. Bijgedragen onderwerp branches samenvoegen in langlopende integratie branches.

Als een onderwerp branch uiteindelijk is samengevoegd in master, dan wordt het verwijderd van het repository. Het Git project heeft ook een main branch, die geforked is van de laatste vrijgave om teruggewerkte patches te leveren in het geval een onderhoudsvrijgave benodigd is. Dus, als je het Git repository cloned, dan heb je vier branches die je kunt uitchecken om het project in verschillende stadia van ontwikkeling te evalueren, afhankelijk van hoe nieuw je alles wilt hebben of hoe je wil bijdragen; en de beheerder heeft een gestructureerde werkwijze om ze te helpen nieuwe bijdragen aan de tand te voelen.

Rebasen en cherry pick werkwijzen

Andere beheerders geven de voorkeur aan rebasen of bijgedragen werk te cherry picken bovenop hun master branch, in plaats van het er in samen te voegen, om een lineaire historie te behouden. Als je werk in een onderwerp branch hebt en hebt besloten dat je het wil integreren, dan ga je naar die branch en voert het rebase commando uit om de wijzigingen bovenop je huidige master branch te bouwen (of develop, enzovoorts). Als dat goed werkt, dan kun je je master branch fast-forwarden, en dan eindig je met een lineaire project historie.

De andere manier om geïntroduceerd werk van de ene naar de andere branch te verplaatsen is om het te cherry picken. Een cherry-pick in Git is een soort rebase voor een enkele commit. Het pakt de patch die was geïntroduceerd in een commit en probeert die opnieuw toe te passen op de branch waar je nu op zit. Dit is handig als je een aantal commits op een onderwerp branch hebt en je er slechts één van wilt integreren, of als je alleen één commit op een onderwerp branch hebt en er de voorkeur aan geeft om het te cherry-picken in plaats van rebase uit te voeren. Bijvoorbeeld, stel dat je een project hebt dat eruit ziet als Figuur 5-26.


Figuur 5-26. Voorbeeld historie voor een cherry pick.

Als je commit e43a6 in je master branch wil halen, dan kun je dit uitvoeren

$ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
 3 files changed, 17 insertions(+), 3 deletions(-)

Dit haalt dezelfde wijziging binnen als geïntroduceerd in e43a6, maar je krijgt een nieuwe SHA-1 waarde, omdat de gegevens op een andere manier toegepast zijn. Nu ziet je historie eruit als Figuur 5-27.


Figuur 5-27. Historie na het cherry-picken van een commit op een onderwerp branch.

Nu kun je je onderwerp branch verwijderen en de commits die je niet wou binnenhalen weggooien.

Je vrijgaven taggen

Als je hebt besloten om een vrijgave te doen, zul je waarschijnlijk een tag willen aanmaken zodat je die vrijgave op ieder punt in de toekomst kunt namaken. Je kunt een nieuwe tag maken zoals ik heb beschreven in Hoofdstuk 2. Als je besluit om de tag als de beheerder te signeren, dan ziet het taggen er misschien zo uit:

$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09

Als je je tags signeert, dan heb je misschien een problem om de publieke PGP sleutel te distribueren, die gebruikt is om de tags te signeren. De beheerder van het Git project heeft dit probleem opgelost door hun publieke sleutel als een blob in het repository mee te nemen en dan een tag toe te voegen die direct naar die inhoud wijst. Om dit te doen kun je uitvinden welke sleutel je wilt door gpg --list-keys uit te voeren:

$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub   1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid                  Scott Chacon <schacon@gmail.com>
sub   2048g/45D02282 2009-02-09 [expires: 2010-02-09]

Daarna kun je de sleutel direct in de Git gegevensbank importeren, door het te exporteren en om te leiden door git hash-object, wat een nieuwe blob schrijft in Git met die inhoud en je de SHA-1 van de blob teruggeeft:

$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92

Nu dat je de inhoud van je sleutel in Git hebt, kun je een tag aanmaken die direct daar naar wijst door de nieuw SHA-1 waarde die het hash-object commando je gaf te specificeren:

$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92

Als je git push --tags uitvoert, zal de maintainer-pgp-pub tag met iedereen gedeeld worden. Als iemand een tag wil verifiëren, dan kunnen ze je PGP sleutel direct importeren door de blob direct uit de gegevensbank te halen en het in GPG te importeren:

$ git show maintainer-pgp-pub | gpg --import

Ze kunnen die sleutel gebruiken om als je gesigneerde tags te verifiëren. Als je de instructies in het tag bericht zet, dan zal git show <tag> je eindgebruikers meer specifieke instructies geven over tag verificatie.

Een bouw nummer genereren

Omdat Git geen monotone oplopende nummers heeft zoals ‘v123’ of iets gelijkwaardigs om bij iedere commit mee te gaan, zul je als je een voor mensen leesbare naam wilt hebben bij een commit, git describe kunnen uitvoeren op die commit. Git geeft je de naam van de dichtstbijzijnde tag met het aantal commits bovenop die dag en een gedeeltelijke SHA-1 waarde van de commit die je omschrijft:

$ git describe master
v1.6.2-rc1-20-g8c5b85c

Op deze manier kun je een snapshot of bouw exporteren en het vernoemen naar iets dat begrijpelijk is voor mensen. In feite, als je Git vanaf broncode bouwt, gecloned van het Git repository, geeft git --version je iets dat er zo uitziet. Als je een commit omschrijft die je direct getagged wil hebben, dat geeft het je de tag naam.

Het git describe commando heeft de voorkeur voor beschreven tags (tags gecreëerd met de -a of -s vlag), dus vrijgave tags zouden op deze manier aangemaakt moeten worden als je git describe gebruikt, om er zeker van te zijn dat de commit juist benoemd wordt als het omschreven wordt. Je kunt deze tekst gebruiken als het doel van een checkout of show commando, alhoewel het afhangt van de verkorte SHA-1 waarde aan het einde, dus het zou niet voor altijd geldig kunnen zijn. Bijvoorbeeld, de Linux kernel sprong recentelijk van 8 naar 10 karakters om er zeker van de zijn dat de SHA-1 uniek zijn, zodat oudere git describe commando’s ongeldig werden.

Een vrijgave voorbereiden

Nu wil je een bouw vrijgeven. Een van de dingen die je wilt doen is een archief maken van het laatste snapshot van je code voor die arme zielen die geen Git gebruiken. Het commando om dit te doen is git archive:

$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz

Als iemand die tarball opent, dan krijgen ze ze laatste snapshot van je project onder een project map. Je kunt op vrijwel dezelfde manier ook een zip archief maken, maar dan door de format=zip optie mee te geven aan git archive:

$ git archive master --prefix='project/' --format=zip > `git describe master`.zip

Je hebt nu een fijne tarball en een zip archief van je project vrijgave, die je kunt uploaden naar je website of naar mensen kunt e-mailen.

Het shortlog

Het is tijd geworden om je maillijst van mensen die willen weten wat er gebeurt in je project te e-mailen. Een fijne manier om een soort van veranderingslog te krijgen van wat er is toegevoegd in je project sinds je laatste vrijgave of e-mail is om het git shortlog commando te gebruiken. Het vat alle commits samen in de reeks die je het geeft; bijvoorbeeld, het volgende geeft je een samenvatting van alle commits sinds je vorige vrijgave, als je laatste vrijgave v1.0.1 heette:

$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (8):
      Add support for annotated tags to Grit::Tag
      Add packed-refs annotated tag support.
      Add Grit::Commit#to_patch
      Update version and History.txt
      Remove stray `puts`
      Make ls_tree ignore nils

Tom Preston-Werner (4):
      fix dates in history
      dynamic version method
      Version bump to 1.0.2
      Regenerated gemspec for version 1.0.2

Je krijgt een schone samenvatting van alle commits sinds v1.0.1, gegroepeerd op auteur, die je naar je lijst kunt e-mailen.