Hoe schrijf je een Git Commit bericht

Inhoud: Introductie | De Zeven Regels | Tips

Inleiding: Waarom goede commit boodschappen belangrijk zijn

Als je door het log van een willekeurige Git repository bladert, zul je waarschijnlijk zien dat de commit boodschappen min of meer een rommeltje zijn. Bijvoorbeeld, kijk eens naar deze juweeltjes uit mijn begintijd met het committen naar Spring:

$ git log --oneline -5 --author cbeams --before "Fri Mar 26 2009"e5f4b49 Re-adding ConfigurationPostProcessorTests after its brief removal in r814. @Ignore-ing the testCglibClassesAreLoadedJustInTimeForEnhancement() method as it turns out this was one of the culprits in the recent build breakage. The classloader hacking causes subtle downstream effects, breaking unrelated tests. The test method is still useful, but should only be run on a manual basis to ensure CGLIB is not prematurely classloaded, and should not be run as part of the automated build.2db0f12 fixed two build-breaking issues: + reverted ClassMetadataReadingVisitor to revision 794 + eliminated ConfigurationPostProcessorTests until further investigation determines why it causes downstream tests to fail (such as the seemingly unrelated ClassPathXmlApplicationContextTests)147709f Tweaks to package-info.java files22b25e0 Consolidated Util and MutableAnnotationUtils classes into existing AsmUtils7f96f57 polishing

Jakkes. Vergelijk dat eens met deze recentere commits uit hetzelfde archief:

$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014"5ba3db6 Fix failing CompositePropertySourceTests84564a0 Rework @PropertySource early parsing logice142fd1 Add tests for ImportSelector meta-data887815f Update docbook dependency and generate epubac8326d Polish mockito usage

Welke zou je liever lezen?

De eerste varieert in lengte en vorm; de tweede is beknopt en consistent.
De eerste is wat er standaard gebeurt; de laatste gebeurt nooit per ongeluk.

Weliswaar zien de logs van veel repositories er uit als de eerste, maar er zijn uitzonderingen. De Linux kernel en Git zelf zijn goede voorbeelden. Kijk naar Spring Boot, of een repository beheerd door Tim Pope.

De bijdragers aan deze repositories weten dat een goed opgesteld Git commit bericht de beste manier is om context over een verandering te communiceren naar mede ontwikkelaars (en inderdaad naar hun toekomstige zelven). Een diff zal je vertellen wat er veranderd is, maar alleen de commit boodschap kan je goed vertellen waarom. Peter Hutterer maakt dit punt goed:

Het opnieuw vaststellen van de context van een stuk code is verspilling. We kunnen het niet helemaal vermijden, dus moeten we ons best doen om het zo veel mogelijk te beperken. Commit boodschappen kunnen precies dat doen en als resultaat laat een commit boodschap zien of een ontwikkelaar een goede medewerker is.

Als je niet veel nagedacht hebt over wat een goede Git commit boodschap maakt, dan kan het zijn dat je niet veel tijd besteed hebt aan het gebruiken van git log en gerelateerde tools. Er is hier sprake van een vicieuze cirkel: omdat de commit geschiedenis ongestructureerd en inconsistent is, besteed je er niet veel tijd aan om het te gebruiken of er zorg voor te dragen. En omdat het niet gebruikt of verzorgd wordt, blijft het ongestructureerd en inconsistent.

Maar een goed verzorgd logboek is een mooi en nuttig ding. git blame, revert, rebase, log, shortlog en andere subcommando’s komen tot leven. Het nakijken van andermans commits en pull requests wordt iets wat het waard is om te doen, en kan ineens onafhankelijk gedaan worden. Begrijpen waarom iets maanden of jaren geleden is gebeurd, wordt niet alleen mogelijk, maar ook efficiënt.

Het succes van een project op de lange termijn berust (onder andere) op de onderhoudbaarheid ervan, en een onderhouder heeft weinig gereedschappen die krachtiger zijn dan het logboek van zijn project. Het is de moeite waard om de tijd te nemen om te leren hoe je er goed voor moet zorgen. Wat in het begin misschien een gedoe is, wordt al snel een gewoonte, en uiteindelijk een bron van trots en productiviteit voor alle betrokkenen.

In dit bericht behandel ik alleen het meest basale element van het bijhouden van een gezonde commit geschiedenis: hoe je een individueel commit bericht schrijft. Er zijn andere belangrijke praktijken, zoals commit squashing, die ik hier niet behandel. Misschien doe ik dat in een volgende post.

De meeste programmeertalen hebben gevestigde conventies over wat een idiomatische stijl is, zoals naamgeving, opmaak, enzovoorts. Er zijn natuurlijk variaties op deze conventies, maar de meeste ontwikkelaars zijn het er over eens dat het veel beter is om er een te kiezen en je daaraan te houden dan de chaos die ontstaat als iedereen zijn eigen ding doet.

De aanpak van een team voor zijn commit log zou niet anders moeten zijn. Om een bruikbare revisie geschiedenis te creëren, zouden teams het eerst eens moeten worden over een vastleggingsconventie die tenminste de volgende drie dingen definieert:

Stijl. Markup syntax, marges, grammatica, hoofdlettergebruik, interpunctie. Leg deze dingen vast, verwijder het giswerk, en maak het allemaal zo simpel mogelijk. Het eindresultaat zal een opmerkelijk consistent logboek zijn dat niet alleen een plezier is om te lezen, maar dat ook werkelijk regelmatig gelezen wordt.

Inhoud. Wat voor soort informatie moet de inhoud van het commit bericht (als die er is) bevatten? Wat moet er niet in staan?

Metadata. Hoe moet er verwezen worden naar issue tracking IDs, pull request nummers, etc.?

Gelukkig genoeg zijn er gevestigde conventies over wat een idiomatische Git commit boodschap maakt. Sterker nog, veel van die conventies worden verondersteld in de manier waarop bepaalde Git commando’s werken. Er is niets dat je opnieuw uit hoeft te vinden. Volg gewoon de zeven regels hieronder en je bent op weg om als een pro te committen.

De zeven regels van een geweldige Git commit boodschap

Houd in gedachten: Dit is allemaal al eens eerder gezegd.

  1. Scheid onderwerp en body met een lege regel
  2. Beperk de onderwerpsregel tot 50 karakters
  3. Hoofdletter in de onderwerpsregel
  4. Eindig de onderwerpsregel niet met een punt
  5. Gebruik de gebiedende wijs in de onderwerpsregel
  6. Wrap de body op 72 karakters
  7. Gebruik de body om uit te leggen wat en waarom vs. hoe

Voorbeeld:

Summarize changes in around 50 characters or lessMore detailed explanatory text, if necessary. Wrap it to about 72characters or so. In some contexts, the first line is treated as thesubject of the commit and the rest of the text as the body. Theblank line separating the summary from the body is critical (unlessyou omit the body entirely); various tools like `log`, `shortlog`and `rebase` can get confused if you run the two together.Explain the problem that this commit is solving. Focus on why youare making this change as opposed to how (the code explains that).Are there side effects or other unintuitive consequences of thischange? Here's the place to explain them.Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary hereIf you use an issue tracker, put references to them at the bottom,like this:Resolves: #123See also: #456, #789

Scheid onderwerp en body met een lege regel

Van de git commit manpage:

Hoewel het niet verplicht is, is het een goed idee om het commit bericht te beginnen met een enkele korte (minder dan 50 karakters) regel die de verandering samenvat, gevolgd door een lege regel en dan een meer diepgaande beschrijving. De tekst tot aan de eerste lege regel in een commit boodschap wordt behandeld als de titel van de commit, en die titel wordt door heel Git gebruikt. Bijvoorbeeld, Git-format-patch(1) zet een commit om in e-mail, en het gebruikt de titel op de onderwerp regel en de rest van de commit in de body.

Ten eerste, niet iedere commit heeft zowel een onderwerp als een body nodig. Soms is een enkele regel prima, vooral als de verandering zo eenvoudig is dat er geen verdere context nodig is. Bijvoorbeeld:

Fix typo in introduction to user guide

Niets meer hoeft gezegd te worden; als de lezer zich afvraagt wat de typfout was, kan ze gewoon naar de wijziging zelf kijken, d.w.z. git show of git diff of git log -p gebruiken.

Als je iets als dit committeert op de commandoregel, is het eenvoudig om de -m optie te gebruiken voor git commit:

$ git commit -m"Fix typo in introduction to user guide"

Als een commit echter een beetje uitleg en context verdient, dan moet je een body schrijven. Bijvoorbeeld:

Derezz the master control programMCP turned out to be evil and had become intent on world domination.This commit throws Tron's disc into MCP (causing its deresolution)and turns it back into a chess game.

Commit boodschappen met body’s zijn niet zo makkelijk te schrijven met de -m optie. U kunt het bericht beter in een goede teksteditor schrijven. Als je nog geen editor hebt ingesteld voor gebruik met Git op de commandoregel, lees dan deze sectie van Pro Git.

In ieder geval, het scheiden van onderwerp en body betaalt zich uit bij het doorbladeren van het log. Hier is de volledige log entry:

$ git logcommit 42e769bdf4894310333942ffc5a15151222a87beAuthor: Kevin Flynn <[email protected]>Date: Fri Jan 01 00:00:00 1982 -0200 Derezz the master control program MCP turned out to be evil and had become intent on world domination. This commit throws Tron's disc into MCP (causing its deresolution) and turns it back into a chess game.

En nu git log --oneline, die alleen de onderwerp regel weergeeft:

$ git log --oneline42e769 Derezz the master control program

Of, git shortlog, die commits per gebruiker groepeert, en weer alleen de onderwerp regel weergeeft voor de beknoptheid:

$ git shortlogKevin Flynn (1): Derezz the master control programAlan Bradley (1): Introduce security program "Tron"Ed Dillinger (3): Rename chess program to "MCP" Modify chess program Upgrade chess programWalter Gibbs (1): Introduce protoype chess program

Er zijn een aantal andere contexten in Git waar het onderscheid tussen onderwerp regel en body in werking treedt- maar geen van hen werkt goed zonder de lege regel ertussen.

Limiteer de onderwerpregel tot 50 karakters

50 karakters is geen harde limiet, slechts een vuistregel. Een onderwerpregel van deze lengte zorgt ervoor dat deze leesbaar is, en dwingt de auteur om even na te denken over de meest beknopte manier om uit te leggen wat er aan de hand is.

Tip: Als je het moeilijk vindt om samen te vatten, committeer je misschien te veel wijzigingen in één keer. Streef naar atomic commits (een onderwerp voor een aparte post).

GitHub’s UI is zich volledig bewust van deze conventies. Hij waarschuwt u als u de limiet van 50 tekens overschrijdt:

En hij kort elke onderwerpregel die langer is dan 72 tekens af met een ellips:

Dus ga voor 50 tekens, maar beschouw 72 als de harde limiet.

Hoofdletter in onderwerpregel

Dit is zo eenvoudig als het klinkt. Begin alle onderwerpregels met een hoofdletter.

Bijvoorbeeld:

  • accelereer naar 88 mijl per uur

In plaats van:

  • accelereer naar 88 mijl per uur

Beëindig de onderwerpregel niet met een punt

Aftekenende leestekens zijn in onderwerpregels overbodig. Bovendien is ruimte kostbaar als je ze tot 50 karakters of minder probeert te beperken.

Voorbeeld:

  • Open de deuren van het podruim

In plaats van:

  • Open de deuren van het podruim.

Gebruik de gebiedende wijs in de onderwerpregel

Imperatieve wijs betekent gewoon “gesproken of geschreven alsof hij een bevel of instructie geeft”. Een paar voorbeelden:

  • Schoon je kamer
  • Doe de deur dicht
  • Haal het vuilnis buiten

Elke van de zeven regels waarover je nu leest, zijn geschreven in de gebiedende wijs (“Wikkel het lichaam in bij 72 tekens”, enz.).

De gebiedende wijs kan een beetje grof klinken; dat is waarom we het niet vaak gebruiken. Maar het is perfect voor Git commit onderwerpregels. Een reden hiervoor is dat Git zelf de gebiedende wijs gebruikt als het een commit namens jou aanmaakt.

Bijv. het standaard bericht dat gemaakt wordt als je git merge gebruikt, luidt:

Merge branch 'myfeature'

En als je git revert gebruikt:

Revert "Add the thing with the stuff"This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

Of als je op de “Samenvoegen” knop klikt op een GitHub pull request:

Merge pull request #123 from someuser/somebranch

Dus als je je commit berichten in de imperatief schrijft, volg je Git’s eigen ingebouwde conventies. Bijvoorbeeld:

  • Refactor subsystem X voor leesbaarheid
  • Update getting started documentation
  • Remove deprecated methods
  • Release version 1.0.0

Het schrijven op deze manier kan in het begin een beetje onhandig zijn. We zijn meer gewend om in de indicatieve stemming te spreken, die gaat over het rapporteren van feiten. Daarom eindigen commit berichten vaak als volgt:

  • Opgeloste bug met Y
  • Gewijzigd gedrag van X

En soms worden commit berichten geschreven als een beschrijving van hun inhoud:

  • Meer fixes voor gebroken dingen
  • Leuke nieuwe API methoden

Om alle verwarring weg te nemen, hier is een simpele regel om het elke keer goed te doen.

Een goed gevormde onderwerpregel van een Git commit moet altijd de volgende zin kunnen completeren:

  • Indien toegepast, zal deze commit je onderwerpregel hier

Voorbeeld:

  • Indien toegepast, zal deze commit subsysteem X refactoren voor leesbaarheid
  • Indien toegepast, zal deze commit de getting started documentatie bijwerken
  • Indien toegepast, zal deze commit afgeschreven methodes verwijderen
  • Indien toegepast, zal deze commit versie 1.0.0
  • Indien toegepast, zal deze commit pull request #123 van user/branch samenvoegen

Merk op dat dit niet werkt voor de andere niet-imperatieve vormen:

  • Indien toegepast, zal deze commit bug met Y repareren
  • Indien toegepast, zal deze commit het gedrag van X veranderen
  • Indien toegepast, zal deze commit meer fixes voor kapotte dingen
  • Indien toegepast, zal deze commit nieuwe API methoden zoet maken

Houd in gedachten: Het gebruik van de gebiedende wijs is alleen belangrijk in de onderwerpregel. Je kunt deze restrictie versoepelen als je de body schrijft.

Wrap de body op 72 karakters

Git wrapt tekst nooit automatisch. Als je de body van een commit bericht schrijft, moet je op de rechter kantlijn letten, en de tekst handmatig omwikkelen.

De aanbeveling is om dit op 72 karakters te doen, zodat Git genoeg ruimte heeft om tekst in te laten springen, en toch alles onder de 80 karakters te houden.

Een goede tekst editor kan hier bij helpen. Het is makkelijk om Vim in te stellen, bijvoorbeeld, om tekst met 72 karakters in te pakken als je een Git commit aan het schrijven bent. Traditioneel gezien zijn IDE’s echter verschrikkelijk slecht in het bieden van slimme ondersteuning voor tekstomloop in commit boodschappen (hoewel IntelliJ IDEA hier in recente versies eindelijk beter in is geworden).

Gebruik de body om uit te leggen wat en waarom vs. hoe

Deze commit van Bitcoin Core is een geweldig voorbeeld van uitleggen wat er veranderd is en waarom:

commit eb0b56b19017ab5c16c745e6da39c53126924ed6Author: Pieter Wuille <[email protected]>Date: Fri Aug 1 22:57:55 2014 +0200 Simplify serialize.h's exception handling Remove the 'state' and 'exceptmask' from serialize.h's stream implementations, as well as related methods. As exceptmask always included 'failbit', and setstate was always called with bits = failbit, all it did was immediately raise an exception. Get rid of those variables, and replace the setstate with direct exception throwing (which also removes some dead code). As a result, good() is never reached after a failure (there are only 2 calls, one of which is in tests), and can just be replaced by !eof(). fail(), clear(n) and exceptions() are just never called. Delete them.

Kijk eens naar de volledige diff en bedenk hoeveel tijd de auteur zijn collega’s en toekomstige committers bespaart door de tijd te nemen om deze context hier en nu te geven. Als hij dat niet zou doen, zou het waarschijnlijk voor altijd verloren gaan.

In de meeste gevallen kun je details weglaten over hoe een wijziging is aangebracht. Code spreekt wat dat betreft over het algemeen voor zich (en als de code zo complex is dat hij in proza moet worden uitgelegd, dan is dat waar broncommentaar voor is). Concentreer je gewoon op het duidelijk maken van de redenen waarom je de verandering in de eerste plaats hebt aangebracht – de manier waarop dingen voor de verandering werkten (en wat daar mis mee was), de manier waarop ze nu werken, en waarom je besloot het op te lossen zoals je deed.

De toekomstige onderhouder die je bedankt kan jezelf zijn!

Tips

Leer te houden van de commandoregel. Laat de IDE achter je.

Om evenveel redenen als er Git subcommando’s zijn, is het verstandig om de commandoregel te omarmen. Git is waanzinnig krachtig; IDE’s zijn dat ook, maar elk op een andere manier. Ik gebruik elke dag een IDE (IntelliJ IDEA) en heb andere uitgebreid gebruikt (Eclipse), maar ik heb nog nooit IDE integratie voor Git gezien die het gemak en de kracht van de commandoregel kon evenaren (als je het eenmaal weet).

Zekere Git-gerelateerde IDE functies zijn van onschatbare waarde, zoals het aanroepen van git rm als je een bestand verwijdert, en de juiste dingen doen met git als je er een hernoemt. Waar alles in duigen valt is wanneer je begint te proberen te committen, mergen, rebasen, of geavanceerde geschiedenis analyse te doen via de IDE.

Wanneer het aankomt op het gebruiken van de volledige kracht van Git, dan is het de command-line helemaal.

Bedenk dat of je nu Bash of Zsh of Powershell gebruikt, er zijn tab completion scripts die veel van de pijn wegnemen van het onthouden van de subcommando’s en switches.

Lees Pro Git

Het Pro Git boek is gratis online beschikbaar, en het is fantastisch. Doe er je voordeel mee!

header image credit: xkcd

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.