Inhalt: Einführung | Die sieben Regeln | Tipps
- Einführung: Warum gute Commit-Nachrichten wichtig sind
- Die sieben Regeln einer guten Git-Commit-Nachricht
- Thema und Textkörper durch eine Leerzeile trennen
- Beschränken Sie die Betreffzeile auf 50 Zeichen
- Großschreibung in der Betreffzeile
- Schließen Sie die Betreffzeile nicht mit einem Punkt ab
- Verwenden Sie den Imperativ in der Betreffzeile
- Den Textkörper mit 72 Zeichen umbrechen
- Benutzen Sie den Hauptteil, um zu erklären, was und warum vs. how
- Tipps
- Lernen Sie die Kommandozeile zu lieben. Lassen Sie die IDE hinter sich.
- Lesen Sie Pro Git
Einführung: Warum gute Commit-Nachrichten wichtig sind
Wenn Sie das Protokoll eines beliebigen Git-Repositorys durchsuchen, werden Sie wahrscheinlich feststellen, dass die Commit-Nachrichten mehr oder weniger durcheinander sind. Werfen Sie zum Beispiel einen Blick auf diese Perlen aus meinen frühen Tagen, als ich zu Spring übertrug:
$ 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
Huch. Vergleichen Sie das mit diesen neueren Commits aus demselben 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
Was würden Sie lieber lesen?
Das erste variiert in Länge und Form; das zweite ist kurz und konsistent.
Das erste ist das, was standardmäßig passiert; das zweite passiert nie zufällig.
Während die Logs vieler Repositories wie das erste aussehen, gibt es Ausnahmen. Der Linux-Kernel und Git selbst sind gute Beispiele dafür. Schauen Sie sich Spring Boot oder ein von Tim Pope verwaltetes Repository an.
Die Mitwirkenden an diesen Repositories wissen, dass eine gut formulierte Git-Commit-Nachricht der beste Weg ist, um anderen Entwicklern (und auch sich selbst in der Zukunft) den Kontext einer Änderung mitzuteilen. Ein diff wird Ihnen sagen, was sich geändert hat, aber nur die Commit Nachricht kann Ihnen richtig sagen warum. Peter Hutterer bringt diesen Punkt gut auf den Punkt:
Die Wiederherstellung des Kontextes eines Stückes Code ist verschwenderisch. Wir können sie nicht vollständig vermeiden, also sollten wir uns bemühen, sie so weit wie möglich zu reduzieren. Commit-Nachrichten können genau das tun, und daher zeigt eine Commit-Nachricht, ob ein Entwickler ein guter Mitarbeiter ist.
Wenn Sie noch nicht viel darüber nachgedacht haben, was eine gute Git-Commit-Nachricht ausmacht, haben Sie vielleicht noch nicht viel Zeit mit git log
und verwandten Tools verbracht. Das ist ein Teufelskreis: Weil die Commit-Historie unstrukturiert und inkonsistent ist, verbringt man nicht viel Zeit damit, sie zu nutzen oder sich um sie zu kümmern. Und weil sie nicht benutzt oder gepflegt wird, bleibt sie unstrukturiert und inkonsistent.
Aber ein gut gepflegtes Protokoll ist eine schöne und nützliche Sache. git blame
, revert
, rebase
, log
, shortlog
und andere Unterbefehle erwachen zum Leben. Das Überprüfen von Commits und Pull-Requests anderer wird zu einer lohnenden Aufgabe, die plötzlich unabhängig erledigt werden kann. Zu verstehen, warum etwas vor Monaten oder Jahren passiert ist, wird nicht nur möglich, sondern auch effizient.
Der langfristige Erfolg eines Projekts hängt (unter anderem) von seiner Wartbarkeit ab, und ein Maintainer hat nur wenige Werkzeuge, die mächtiger sind als das Protokoll seines Projekts. Es lohnt sich, die Zeit zu nehmen, um zu lernen, wie man es richtig pflegt. Was anfangs vielleicht lästig ist, wird bald zur Gewohnheit, und schließlich zu einer Quelle des Stolzes und der Produktivität für alle Beteiligten.
In diesem Beitrag spreche ich nur das grundlegendste Element einer gesunden Commit-Historie an: wie man eine individuelle Commit-Nachricht schreibt. Es gibt noch andere wichtige Praktiken wie Commit Squashing, die ich hier nicht anspreche. Vielleicht werde ich das in einem späteren Beitrag tun.
Die meisten Programmiersprachen haben gut etablierte Konventionen darüber, was einen idiomatischen Stil ausmacht, d.h. Benennung, Formatierung und so weiter. Es gibt natürlich Variationen dieser Konventionen, aber die meisten Entwickler sind sich einig, dass es besser ist, sich für eine zu entscheiden und sich daran zu halten, als das Chaos, das entsteht, wenn jeder sein eigenes Ding macht.
Ein Team sollte nicht anders mit seinem Commit-Log umgehen. Um eine nützliche Revisionshistorie zu erstellen, sollten sich Teams zuerst auf eine Konvention für Commit-Nachrichten einigen, die mindestens die folgenden drei Dinge definiert:
Stil. Markup-Syntax, Umbruchränder, Grammatik, Großschreibung, Zeichensetzung. Schreiben Sie diese Dinge aus, nehmen Sie das Rätselraten heraus und machen Sie alles so einfach wie möglich. Das Endergebnis wird ein bemerkenswert konsistentes Protokoll sein, das nicht nur angenehm zu lesen ist, sondern auch tatsächlich regelmäßig gelesen wird.
Inhalt. Welche Art von Informationen sollte der Hauptteil der Commit-Nachricht (wenn überhaupt) enthalten? Was sollte sie nicht enthalten?
Metadaten. Wie sollte auf Issue-Tracking-IDs, Pull-Request-Nummern usw. verwiesen werden?
Glücklicherweise gibt es gut etablierte Konventionen darüber, was eine idiomatische Git-Commit-Nachricht ausmacht. Viele dieser Konventionen werden sogar in der Funktionsweise bestimmter Git-Befehle vorausgesetzt. Sie müssen also nichts neu erfinden. Befolgen Sie einfach die folgenden sieben Regeln und Sie sind auf dem besten Weg, wie ein Profi zu committen.
Die sieben Regeln einer guten Git-Commit-Nachricht
Denken Sie daran: Das wurde alles schon einmal gesagt.
- Trenn den Betreff vom Text mit einer Leerzeile
- Beschränken Sie die Betreffzeile auf 50 Zeichen
- Schreiben Sie die Betreffzeile in Großbuchstaben
- Schließen Sie die Betreffzeile nicht mit einem Punkt ab
- Verwenden Sie den Imperativ in der Betreffzeile
- Beschränken Sie den Text auf 72 Zeichen
- Erläutern Sie im Text, was und warum vs. wie
Zum Beispiel:
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
Thema und Textkörper durch eine Leerzeile trennen
Aus der git commit
Manpage:
Auch wenn es nicht erforderlich ist, ist es eine gute Idee, die Commit-Nachricht mit einer einzelnen kurzen (weniger als 50 Zeichen) Zeile zu beginnen, die die Änderung zusammenfasst, gefolgt von einer Leerzeile und dann einer ausführlicheren Beschreibung. Der Text bis zur ersten Leerzeile in einer Commit-Nachricht wird als Commit-Titel behandelt, und dieser Titel wird in ganz Git verwendet. Git-format-patch(1) wandelt zum Beispiel einen Commit in eine E-Mail um und verwendet den Titel in der Betreffzeile und den Rest des Commits im Textkörper.
Erstens, nicht jeder Commit benötigt sowohl einen Betreff als auch einen Textkörper. Manchmal reicht eine einzige Zeile, vor allem wenn die Änderung so einfach ist, dass kein weiterer Kontext notwendig ist. Zum Beispiel:
Fix typo in introduction to user guide
Es muss nichts weiter gesagt werden; wenn der Leser sich fragt, was der Tippfehler war, kann er einfach einen Blick auf die Änderung selbst werfen, d.h. git show
oder git diff
oder git log -p
verwenden.
Wenn Sie so etwas auf der Kommandozeile übertragen, ist es einfach, die Option -m
für git commit
zu verwenden:
$ git commit -m"Fix typo in introduction to user guide"
Wenn jedoch eine Übertragung ein wenig Erklärung und Kontext verdient, müssen Sie einen Körper schreiben. Zum Beispiel:
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-Nachrichten mit Body sind mit der Option -m
nicht so einfach zu schreiben. Es ist besser, die Nachricht in einem richtigen Texteditor zu schreiben. Wenn Sie noch keinen Editor für die Verwendung mit Git auf der Kommandozeile eingerichtet haben, lesen Sie diesen Abschnitt von Pro Git.
In jedem Fall zahlt sich die Trennung von Betreff und Textkörper beim Durchsuchen des Protokolls aus. Hier ist der vollständige Protokolleintrag:
$ 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.
Und jetzt git log --oneline
, das nur die Betreffzeile ausgibt:
$ git log --oneline42e769 Derezz the master control program
Oder git shortlog
, das Commits nach Benutzer gruppiert und ebenfalls nur die Betreffzeile anzeigt, um die Übersichtlichkeit zu wahren:
$ 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
Es gibt noch eine Reihe anderer Kontexte in Git, in denen die Unterscheidung zwischen Betreffzeile und Hauptteil zum Tragen kommt – aber keiner von ihnen funktioniert richtig ohne die Leerzeile dazwischen.
Beschränken Sie die Betreffzeile auf 50 Zeichen
50 Zeichen sind keine feste Grenze, sondern nur eine Faustregel. Betreffzeilen in dieser Länge stellen sicher, dass sie lesbar sind, und zwingen den Autor dazu, einen Moment darüber nachzudenken, wie er am besten erklären kann, was vor sich geht.
Tipp: Wenn es Ihnen schwer fällt, eine Zusammenfassung zu erstellen, übertragen Sie vielleicht zu viele Änderungen auf einmal. Bemühen Sie sich um atomare Übertragungen (ein Thema für einen separaten Beitrag).
Die Benutzeroberfläche von GitHub ist sich dieser Konventionen voll bewusst. Es warnt Sie, wenn Sie die 50-Zeichen-Grenze überschreiten:
Und schneidet jede Betreffzeile, die länger als 72 Zeichen ist, mit einer Ellipse ab:
So versuchen Sie, 50 Zeichen zu erreichen, aber betrachten Sie 72 als harte Grenze.
Großschreibung in der Betreffzeile
Das ist so einfach, wie es klingt. Beginnen Sie alle Betreffzeilen mit einem Großbuchstaben.
Zum Beispiel:
- Beschleunigen Sie auf 88 Meilen pro Stunde
Anstatt:
- Beschleunigen Sie auf 88 Meilen pro Stunde
Schließen Sie die Betreffzeile nicht mit einem Punkt ab
Folgende Satzzeichen sind in Betreffzeilen unnötig. Außerdem ist Platz kostbar, wenn man versucht, sie auf 50 Zeichen oder weniger zu beschränken.
Beispiel:
- Öffnen Sie die Türen des Gondelraums
Anstatt:
- Öffnen Sie die Türen des Gondelraums.
Verwenden Sie den Imperativ in der Betreffzeile
Imperativ bedeutet einfach „gesprochen oder geschrieben, als ob man einen Befehl oder eine Anweisung gibt“. Ein paar Beispiele:
- Reinige dein Zimmer
- Schließe die Tür
- Nimm den Müll mit
Jede der sieben Regeln, über die du gerade liest, ist im Imperativ geschrieben („Wickle den Körper bei 72 Zeichen ein“, usw.).
Der Imperativ kann ein wenig unhöflich klingen; deshalb verwenden wir ihn nicht oft. Aber er ist perfekt für die Betreffzeilen von Git-Commits. Ein Grund dafür ist, dass Git selbst den Imperativ verwendet, wenn es einen Commit in Ihrem Namen erstellt.
Die Standardnachricht, die bei der Verwendung von git merge
erstellt wird, lautet zum Beispiel:
Merge branch 'myfeature'
Und bei der Verwendung von git revert
:
Revert "Add the thing with the stuff"This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.
Oder beim Klicken auf die Schaltfläche „Merge“ in einer GitHub-Pull-Anfrage:
Merge pull request #123 from someuser/somebranch
Wenn Sie also Ihre Commit-Nachrichten im Imperativ schreiben, folgen Sie den in Git eingebauten Konventionen. Zum Beispiel:
- Refactor subsystem X for readability
- Update getting started documentation
- Remove deprecated methods
- Release version 1.0.0
Diese Art zu schreiben kann anfangs etwas unangenehm sein. Wir sind es eher gewohnt, im Indikativ zu sprechen, in dem es um die Angabe von Fakten geht. Deshalb lesen sich Commit-Nachrichten oft so:
- Fehler mit Y behoben
- Verändertes Verhalten von X
Und manchmal werden Commit-Nachrichten als Beschreibung ihres Inhalts geschrieben:
- Mehr Korrekturen für kaputte Sachen
- Süße neue API-Methoden
Um jegliche Verwirrung zu beseitigen, hier eine einfache Regel, um es jedes Mal richtig zu machen.
Eine richtig geformte Git-Commit-Betreffszeile sollte immer in der Lage sein, den folgenden Satz zu vervollständigen:
- Wenn angewendet, wird dieser Commit Ihre Betreffzeile hier
Zum Beispiel:
- Wenn angewandt, wird dieser Commit das Subsystem X zur besseren Lesbarkeit überarbeiten
- Wenn angewandt, wird dieser Commit die Dokumentation zu den ersten Schritten aktualisieren
- Wenn angewandt, wird dieser Commit veraltete Methoden entfernen
- Wenn angewandt, wird dieser Commit die Version 1.0.0
- Wenn angewandt, wird dieser Commit den Pull Request #123 von user/branch zusammenführen
Beachte, dass dies nicht für die anderen nicht-imperativen Formen funktioniert:
- Wenn angewandt, wird dieser Commit einen Fehler mit Y beheben
- Wenn angewandt, wird dieser Commit das Verhalten von X ändern
- Wenn angewandt, wird dieser Commit weitere Fehler beheben
- Wenn angewandt, wird dieser Commit neue API-Methoden süßen
Erinnern Sie sich: Die Verwendung des Imperativs ist nur in der Betreffzeile wichtig. Sie können diese Einschränkung lockern, wenn Sie den Textkörper schreiben.
Den Textkörper mit 72 Zeichen umbrechen
Git bricht Text nie automatisch um. Wenn Sie den Textkörper einer Commit-Nachricht schreiben, müssen Sie den rechten Rand beachten und den Text manuell umbrechen.
Die Empfehlung ist, dies bei 72 Zeichen zu tun, so dass Git viel Platz hat, um den Text einzurücken und trotzdem alles unter 80 Zeichen zu halten.
Ein guter Texteditor kann hier helfen. Es ist einfach, z.B. Vim so zu konfigurieren, dass er Text mit 72 Zeichen umbricht, wenn Sie eine Git-Übertragung schreiben. Traditionell sind IDEs jedoch schrecklich darin, intelligente Unterstützung für Textumbrüche in Commit-Nachrichten zu bieten (obwohl IntelliJ IDEA in den letzten Versionen endlich besser geworden ist).
Benutzen Sie den Hauptteil, um zu erklären, was und warum vs. how
Dieser Commit von Bitcoin Core ist ein großartiges Beispiel dafür, wie man erklärt, was sich geändert hat und warum:
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.
Werfen Sie einen Blick auf den vollständigen Diff und denken Sie daran, wie viel Zeit der Autor seinen Kollegen und zukünftigen Committern spart, indem er sich die Zeit nimmt, diesen Kontext hier und jetzt zu liefern. Wenn er es nicht täte, wäre es wahrscheinlich für immer verloren.
In den meisten Fällen kann man Details darüber weglassen, wie eine Änderung gemacht wurde. Code ist in dieser Hinsicht in der Regel selbsterklärend (und wenn der Code so komplex ist, dass er in Prosa erklärt werden muss, ist das die Aufgabe der Quelltextkommentare). Konzentrieren Sie sich einfach darauf, deutlich zu machen, warum Sie die Änderung überhaupt gemacht haben – wie die Dinge vor der Änderung funktionierten (und was daran falsch war), wie sie jetzt funktionieren, und warum Sie sich entschieden haben, es so zu lösen, wie Sie es getan haben.
Der zukünftige Betreuer, der Ihnen dankt, könnte Sie selbst sein!
Tipps
Lernen Sie die Kommandozeile zu lieben. Lassen Sie die IDE hinter sich.
Aus so vielen Gründen wie es Git-Unterbefehle gibt, ist es klug, die Kommandozeile zu lieben. Git ist wahnsinnig mächtig; IDEs sind es auch, aber jede auf ihre eigene Art. Ich benutze jeden Tag eine IDE (IntelliJ IDEA) und habe andere ausgiebig benutzt (Eclipse), aber ich habe noch nie eine IDE-Integration für Git gesehen, die auch nur annähernd mit der Einfachheit und Mächtigkeit der Kommandozeile mithalten kann (wenn man sie erst einmal kennt).
Bestimmte IDE-Funktionen im Zusammenhang mit Git sind von unschätzbarem Wert, wie z.B. der Aufruf von git rm
, wenn man eine Datei löscht, und das richtige Verhalten mit git
, wenn man eine Datei umbenennt. Der Punkt, an dem alles zusammenbricht, ist, wenn man versucht, über die IDE zu committen, zu mergen, zu rebasen oder eine ausgeklügelte Verlaufsanalyse durchzuführen.
Wenn es darum geht, die volle Macht von Git zu nutzen, ist die Kommandozeile der richtige Weg.
Denken Sie daran, dass es unabhängig davon, ob Sie Bash, Zsh oder Powershell verwenden, Skripte zur Vervollständigung der Tabulatoren gibt, die Ihnen das Erinnern an die Unterbefehle und Schalter abnehmen.
Lesen Sie Pro Git
Das Buch Pro Git ist online kostenlos erhältlich und es ist fantastisch. Nutzen Sie es aus!
header image credit: xkcd