Hvordan man skriver en Git Commit-meddelelse

Indhold: Introduktion | De syv regler | Tips

Introduktion:

: Hvorfor gode commit-meddelelser er vigtige

Hvis du gennemser loggen for et tilfældigt Git-repositorium, vil du sandsynligvis opdage, at dets commit-meddelelser er mere eller mindre et rod. Tag f.eks. et kig på disse perler fra mine tidlige dage med at committe til 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

Yikes. Sammenlign det med disse nyere commits fra samme repository:

$ 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

Hvilken vil du hellere læse?

Den førstnævnte varierer i længde og form; den sidstnævnte er kortfattet og konsekvent.
Den førstnævnte er det, der sker som standard; den sidstnævnte sker aldrig ved et uheld.

Mens mange repositoriers logs ligner den førstnævnte, er der undtagelser. Linux-kernen og Git selv er gode eksempler. Se på Spring Boot eller ethvert repository, der administreres af Tim Pope.

Medarbejderne til disse repositories ved, at en velformuleret Git commit-meddelelse er den bedste måde at kommunikere kontekst om en ændring til andre udviklere (og faktisk til dem selv i fremtiden). En diff fortæller dig, hvad der er ændret, men kun en commit-meddelelse kan fortælle dig ordentligt hvorfor. Peter Hutterer gør denne pointe godt:

Det er spild af tid at genetablere konteksten for et stykke kode. Vi kan ikke undgå det helt, så vores indsats bør gå til at reducere det så meget som muligt. Commit-meddelelser kan gøre præcis det, og som følge heraf viser en commit-meddelelse, om en udvikler er en god samarbejdspartner.

Hvis du ikke har gjort dig mange tanker om, hvad der gør en god Git commit-meddelelse, kan det være, at du ikke har brugt meget tid på at bruge git log og relaterede værktøjer. Der er en ond cirkel her: Fordi commit-historikken er ustruktureret og inkonsekvent, bruger man ikke meget tid på at bruge eller tage sig af den. Og fordi man ikke bruger den eller tager sig af den, forbliver den ustruktureret og inkonsekvent.

Men en velplejet log er en smuk og nyttig ting. git blame, revert, rebase, log, shortlog og andre underkommandoer kommer til live. Gennemgang af andres commits og pull requests bliver noget, der er værd at gøre, og som pludselig kan gøres uafhængigt af hinanden. At forstå, hvorfor noget skete for måneder eller år siden, bliver ikke blot muligt, men også effektivt.

Et projekts langsigtede succes hviler (blandt andet) på dets vedligeholdbarhed, og en vedligeholder har få værktøjer, der er mere effektive end hans projekts log. Det er værd at tage sig tid til at lære, hvordan man passer en sådan ordentligt. Hvad der i starten kan være besværligt, bliver hurtigt til en vane og i sidste ende en kilde til stolthed og produktivitet for alle involverede.

I dette indlæg tager jeg kun fat på det mest grundlæggende element i at holde en sund commit-historik: hvordan man skriver en individuel commit-meddelelse. Der er andre vigtige praksisser som commit squashing, som jeg ikke tager fat på her. Måske vil jeg gøre det i et senere indlæg.

De fleste programmeringssprog har veletablerede konventioner for, hvad der udgør idiomatisk stil, dvs. navngivning, formatering og så videre. Der er naturligvis variationer af disse konventioner, men de fleste udviklere er enige om, at det er langt bedre at vælge en og holde sig til den end det kaos, der opstår, når alle gør deres egne ting.

Et holds tilgang til sin commit-log bør ikke være anderledes. For at skabe en nyttig revisionshistorik bør holdene først blive enige om en konvention for commit-meddelelser, som definerer mindst følgende tre ting:

Stil. Markup syntaks, wrap marginer, grammatik, kapitalisering, tegnsætning. Skriv disse ting ud, fjern gætteriet, og gør det hele så enkelt som muligt. Slutresultatet vil være en bemærkelsesværdigt konsistent logbog, der ikke blot er en fornøjelse at læse, men som faktisk bliver læst regelmæssigt.

Indhold. Hvilken slags information skal commit-meddelelsens krop (hvis nogen) indeholde? Hvad skal den ikke indeholde?

Metadata. Hvordan skal der henvises til issue tracking ID’er, pull request-numre osv.?

Der er heldigvis veletablerede konventioner for, hvad der udgør en idiomatisk Git commit-meddelelse. Mange af dem forudsættes faktisk i den måde, som visse Git-kommandoer fungerer på. Der er ikke noget, du behøver at genopfinde. Følg blot nedenstående syv regler, så er du på vej til at committe som en professionel.

De syv regler for en god Git commit-meddelelse

Hold dig for øje: Dette er alt sammen blevet sagt før.

  1. Separer emne og brødtekst med en tom linje
  2. Begræns emnelinjen til 50 tegn
  3. Begræns emnelinjen med store bogstaver
  4. Slut ikke emnelinjen med et punktum
  5. Brug den imperative stemning i emnelinjen
  6. Begræns brødteksten til 72 tegn
  7. Brug brødteksten til at forklare hvad og hvorfor i stedet for at forklare hvad og hvorfor
  8. . hvordan

For eksempel:

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

Separer emne fra brødtekst med en tom linje

Fra git commit manpage:

Og selv om det ikke er påkrævet, er det en god idé at begynde commit-meddelelsen med en enkelt kort linje (mindre end 50 tegn), der opsummerer ændringen, efterfulgt af en tom linje og derefter en mere grundig beskrivelse. Teksten op til den første tomme linje i en commit-meddelelse behandles som commit-titlen, og denne titel bruges i hele Git. Git-format-patch(1) forvandler f.eks. en commit til en e-mail, og den bruger titlen på emnelinjen og resten af commit’en i brødteksten.

For det første er det ikke alle commit’er, der kræver både et emne og en brødtekst. Nogle gange er det fint med en enkelt linje, især når ændringen er så simpel, at der ikke er behov for yderligere kontekst. For eksempel:

Fix typo in introduction to user guide

Det er ikke nødvendigt at sige mere; hvis læseren undrer sig over, hvad skrivefejlen var, kan hun blot tage et kig på selve ændringen, dvs. bruge git show eller git diff eller git log -p.

Hvis du committerer noget som dette på kommandolinjen, er det nemt at bruge -m-indstillingen til git commit:

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

Men når en commit fortjener en smule forklaring og kontekst, er du nødt til at skrive en body. For eksempel:

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-meddelelser med bodies er ikke så nemme at skrive med -m-indstillingen. Du er bedre tjent med at skrive meddelelsen i en ordentlig teksteditor. Hvis du ikke allerede har en editor, der er konfigureret til brug med Git på kommandolinjen, skal du læse dette afsnit i Pro Git.

Under alle omstændigheder betaler det sig at adskille emne fra krop, når du gennemser loggen. Her er den fulde logpost:

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

Og nu git log --oneline, som kun udskriver emnelinjen:

$ git log --oneline42e769 Derezz the master control program

Og git shortlog, som grupperer commits efter bruger, og som igen kun viser emnelinjen af hensyn til overskueligheden:

$ 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

Der er en række andre sammenhænge i Git, hvor sondringen mellem emnelinje og brødtekst slår igennem – men ingen af dem fungerer ordentligt uden den tomme linje i mellem.

Begræns emnelinjen til 50 tegn

50 tegn er ikke en hård grænse, men blot en tommelfingerregel. Hvis du holder emnelinjerne på denne længde, sikrer du, at de er læsbare, og tvinger forfatteren til at tænke et øjeblik over den mest koncise måde at forklare, hvad der foregår på.

Tip: Hvis du har svært ved at opsummere, er du måske ved at foretage for mange ændringer på en gang. Stræb efter atomic commits (et emne til et separat indlæg).

GitHubs brugergrænseflade er fuldt ud opmærksom på disse konventioner. Den advarer dig, hvis du overskrider grænsen på 50 tegn:

Og afkorter enhver emnelinje, der er længere end 72 tegn, med en ellipse:

Så skyd efter 50 tegn, men betragt 72 som den hårde grænse.

Gør emnelinjen stor

Dette er lige så simpelt, som det lyder. Begynd alle emnelinjer med et stort bogstav.

For eksempel:

  • Accelerate to 88 miles per hour

I stedet for:

  • accelerate to 88 miles per hour

Afslut ikke emnelinjen med et punktum

Sluttende tegnsætning er unødvendig i emnelinjer. Desuden er pladsen kostbar, når du forsøger at holde dem på 50 tegn eller mindre.

Eksempel:

  • Opnå pod bay-dørene

I stedet for:

  • Opnå pod bay-dørene.

Brug den imperative stemning i emnefeltet

Imperativ stemning betyder blot “talt eller skrevet som om man giver en befaling eller en instruktion”. Et par eksempler:

  • Rengør dit værelse
  • Slut døren
  • Tag skraldet ud

Hver af de syv regler, som du læser om lige nu, er skrevet i imperativ (“Pak kroppen ind ved 72 tegn”, osv.).

Imperativ kan lyde lidt uhøfligt; derfor bruger vi det ikke så ofte. Men det er perfekt til Git commit-emnelinjer. En af grundene til dette er, at Git selv bruger imperativet, når det opretter et commit på dine vegne.

For eksempel lyder standardbeskeden, der oprettes, når du bruger git merge:

Merge branch 'myfeature'

Og når du bruger git revert:

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

Og når du klikker på “Merge”-knappen på en GitHub pull request:

Merge pull request #123 from someuser/somebranch

Så når du skriver dine commit-beskeder i imperativ, følger du Gits egne indbyggede konventioner. For eksempel:

  • Refactor subsystem X for læsbarhed
  • Update getting started documentation
  • Remove deprecated methods
  • Release version 1.0.0

At skrive på denne måde kan være lidt besværligt i starten. Vi er mere vant til at tale i indikativstemning, som handler om at rapportere fakta. Det er derfor, at commit-meddelelser ofte ender med at lyde sådan her:

  • Fixed bug with Y
  • Changing behavior of X

Og nogle gange bliver commit-meddelelser skrevet som en beskrivelse af deres indhold:

  • Mere rettelser til ødelagte ting
  • Søde nye API-metoder

For at fjerne enhver forvirring, er her en simpel regel for at få det rigtigt hver gang.

En korrekt udformet Git commit-emnelinje bør altid kunne udfylde følgende sætning:

  • Hvis det anvendes, vil denne commit din emnelinje her

For eksempel:

  • Hvis det anvendes, vil dette commit refaktorisere delsystem X for at gøre det lettere at læse
  • Hvis det anvendes, vil dette commit opdatere “Getting started”-dokumentationen
  • Hvis det anvendes, vil dette commit fjerne forældede metoder
  • Hvis det anvendes, vil dette commit frigive version 1.0.0
  • Hvis det anvendes, vil dette commit flette pull request #123 fra user/branch

Bemærk, at dette ikke virker for de andre ikke-imperative former:

  • Hvis det anvendes, vil dette commit rette fejl med Y
  • Hvis det anvendes, vil dette commit ændre adfærd for X
  • Hvis det anvendes, vil dette commit rette flere rettelser til ødelagte ting
  • Hvis det anvendes, vil dette commit søde nye API-metoder

Husk: Brug af imperativ er kun vigtig i emnelinjen. Du kan slække på denne begrænsning, når du skriver brødteksten.

Bryd brødteksten ved 72 tegn

Git ombryder aldrig tekst automatisk. Når du skriver kroppen af en commit-meddelelse, skal du passe på dens højre margen og ombryde teksten manuelt.

Anbefalingen er at gøre dette ved 72 tegn, så Git har masser af plads til at indrykke tekst, mens det hele stadig holdes under 80 tegn samlet set.

En god teksteditor kan hjælpe her. Det er f.eks. nemt at konfigurere Vim til at ombryde tekst med 72 tegn, når du skriver en Git commit. Traditionelt har IDE’er dog været forfærdelige til at levere smart understøttelse af tekstombrydning i commit-meddelelser (selv om IntelliJ IDEA i de seneste versioner endelig er blevet bedre til dette).

Brug kroppen til at forklare hvad og hvorfor vs. hvordan

Denne commit fra Bitcoin Core er et godt eksempel på at forklare, hvad der blev ændret og hvorfor:

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.

Tag et kig på den fulde diff og tænk på, hvor meget tid forfatteren sparer sine kolleger og fremtidige commitere ved at tage sig tid til at give denne kontekst her og nu. Hvis han ikke gjorde det, ville den sandsynligvis være tabt for evigt.

I de fleste tilfælde kan du udelade detaljer om, hvordan en ændring er blevet foretaget. Kode er generelt selvforklarende i denne henseende (og hvis koden er så kompleks, at den skal forklares i prosa, er det, hvad kildekommentarer er til). Fokuser blot på at gøre det klart, hvorfor du har foretaget ændringen i første omgang – hvordan tingene fungerede før ændringen (og hvad der var galt med det), hvordan de fungerer nu, og hvorfor du besluttede at løse det på den måde, du gjorde.

Den fremtidige vedligeholder, der takker dig, er måske dig selv!

Tips

Lær at elske kommandolinjen. Lad IDE’en ligge bag dig.

Af lige så mange grunde, som der er Git-underkommandoer, er det klogt at omfavne kommandolinjen. Git er vanvittigt kraftfuldt; IDE’er er også, men hver især på forskellige måder. Jeg bruger et IDE hver dag (IntelliJ IDEA) og har brugt andre i stor udstrækning (Eclipse), men jeg har aldrig set IDE-integration til Git, der kunne begynde at matche kommandolinjens lethed og kraft (når man først kender den).

Visse Git-relaterede IDE-funktioner er uvurderlige, som at kalde git rm, når du sletter en fil, og gøre det rigtige med git, når du omdøber en fil. Der, hvor det hele falder fra hinanden, er, når du begynder at forsøge at commit, merge, rebase eller lave sofistikerede historikanalyser gennem IDE’et.

Når det kommer til at svinge den fulde kraft af Git, er det kommandolinjen hele vejen.

Husk, at uanset om du bruger Bash eller Zsh eller Powershell, er der tab completion scripts, der tager meget af smerten ud af at huske underkommandoer og switches.

Læs Pro Git

Bogen Pro Git er tilgængelig online gratis, og den er fantastisk. Udnyt den!

Header image credit: xkcd

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.