Commits und Commit-Nachrichten

Hallo zusammen,heute beschäftigen wir uns mit Commits und Commit-Nachrichten. Damit du auch gute Nachrichten schreibst, die dir und deinem Team bei der Arbeit helfen. Lerne einfache Konventionen und Methoden, um den Inhalt und die Form deine Nachrichten einer höheren Qualität zu geben. Lass dir erzählen, was man alles damit machen und erreichen kann.
Alexandre Soler Sanandres
Alexandre Soler Sanandres
Beispiel einer Commit Nachricht
Inhalt

Willkommen

Hi, du verwendest git oder eine andere Versionsverwaltung? Dann ist diese Folge etwas für dich. Wir beschäftigen uns heute mit einem Thema, dem manchmal zu wenig Beachtung gescheckt wird: „Commit-Nachrichten“. Die Sache ist nicht unbedingt neu, aber in meinen Augen durchaus aktuell, wichtig und interessant. Darüber hinaus machen wir einen kleinen Abstecher zum Thema Versionsnummern.

Am Ende des Artikels weißt du, was diese Commit Nachrichten sind, warum sie wichtig sind und kennst ein paar Mittel und Wege, um sie besser zu gestalten. Das versetzt dich in der Lage, die teaminterne Kommunikation zu verbessern, eine „technische Dokumentation“ deines Projektes on the Fly zu erstellen und ein paar anderen Vorteilen daraus zu ziehen.

Intro

Wenn du mit git arbeitest, kennst du mit Sicherheit die Pflichtnachricht, die bei jedem Commit dazu gehört. Andere Tools verwenden auch solche Nachrichten. Wichtig ist, dass ein Text mitgeschickt wird, um die Änderungen zu beschreiben. Das ist die Commit-Nachricht. Für manchen ist das ein notwendiges Übel, andere finden es sinnvoll und hilfreich. Ich gehöre eher zu der zweite Fraktion.

Gute Commit-Nachrichten bringen uns größere Vorteile und wir sollten diese auch nutzen. Dafür eignen sich einige Konventionen gut, welche uns am Ende des Tages die Arbeit erleichtern. Aber lass mich euch von einer Situation erzählen, dass wir in meinem Team vor nicht allzu lange Zeit hatten.

Eine kleine Geschichte

Es war Dezember. Wir hatten vor kurzem ein neues Projekt gestartet und wollten nicht während die Weihnachtszeit alles liegen und stehen lassen. Also haben wir hin und her getrickst und den Urlaub so gelegt, dass jederzeit mindestens eine von uns in der Arbeit war. Zwischen Weihnachten und Sylvester war nur Kollege eingeteilt.

Dann war es soweit, die Woche kam und da stand er und wollte mit der Arbeit beginnen. Wir hatten ihn natürlich, mündlich oder per E-Mail, die eine oder andere Information bereits mitgeteilt. Der Stand der Entwicklung war also klar.

Weit gefehlt. Wir hatten nicht so sauber gearbeitet, wie wir dachten. Festzustellen welche Tickets bearbeitet werden können und welche nicht, war wohl schwieriger, als wir gedacht hätten. Da war er voller Elan und stellte fest, „Hoppla, ich weiss doch gar nicht wo ich anfangen soll“. Es hat ihm Zeit und Mühe gekostet, die nötige Infos herauszufinden. Wie du dir vorstellen kannst, das macht nicht wirklich schneller.

Nach dem Urlaub, als wir alle wieder da waren, hat er uns erzählt, welche Schwierigkeiten er gehabt hatte. Sofort war uns klar: Hier ist Verbesserungspotenzial. Eine der Sachen, die wir als Team erreichen möchten, ist das jederzeit, ein Teamkollege für uns einspringen kann, wenn es notwendig ist.

Er hat uns erklärt, „Ich habe versucht in Erfahrung zu bringen wo ich ansetzen kann. Als ich die Tickets und deren Commit Historie geprüft habe, ist mir aufgefallen, dass der Informationsgehalt sehr dürftig war und ich nicht genau wusste was alles passiert war. Das hat mich dazu gezwungen, den Code durchschauen zu müssen, um es rauszufinden“.

Leider hatte er recht. Unsere Commits waren alles andere als optimal. Wir hatten uns keine Konventionen dafür gegeben, so dass jeder von uns anders formatiert und geschrieben hat, was ihm gerade in den Sinn kam. Wir haben uns entschieden die Qualität unsere Commit-Nachrichten in die Höhe zu treiben. Die Commit Historie muss uns helfen zu verstehen, was im Projekt geschieht ohne im Code nachschauen zu müssen. Versteht mich nicht falsch, im Code zu schauen ist völlig ok, aber es soll nicht die einzige Möglichkeit sein.

Wir haben uns Rat geholt. Sowohl aus alte Erfahrungen wie auch vom Internet. Sind dann in uns gegangen und haben einige Mittel gefunden, um die Umstände zu verbessern. Eins davon ist „Conventional Commits“.

Nun haben wir diese Konventionen umgesetzt. Das ist nicht immer leicht. Wir kämpfen immer wieder mit dem inneren Schweinehund und die alten Gewohnheiten. Es ist nicht leicht, etwas zu ändern aber nach einiges Hin und Her ist es uns gelungen. Ich bin froh, dass wir diesen Weg gegangen sind. Unsere Commit-Nachrichten sind aufgeräumter, einheitlich formatiert und der Informationsgehalt ist deutlich besser geworden.

Aber warum erzähle ich euch das Alles? Was versteckt sich hinter dieser Gesichte?

Über Commits und Commit-Nachrichten

Die Commit Historie ist die Summe aller Commit-Nachrichten im Projekt. Sie ist ein Werkzeug der Entwicklung, denn sie hilft uns zu verstehen, wie das Projekt fortschreitet. Sie zeigt uns, was sich geändert hat, wie es sich geändert hat und warum. Sie verrät uns welche neue Funktionalität dazu gekommen ist und welchen Mehrwert wir damit geschaffen haben. Sie ist nützlich, wenn wir in einem neuen Projekt einsteigen oder auf Fehlersuche sind oder einen Review vornehmen möchten.

Ich habe in meinem Leben viel zu viele grässliche Commit-Nachrichten gesehen. Ja, sogar manche selbst geschrieben. Es ist nötig, auch dort eine gewisse Qualität einfließen zu lassen. Aber wie definiere ich ein schlechten Commit. Hier ein paar Beispiele, die ich gesehen habe, oder mir erzählt worden sind:

  • Einfach ein Leerzeichen, sonst nichts.
  • Einen Punkt, um halt was rein zu tun, die Nachricht darf ja nicht leer sein.
  • Einfache Texte wie „Klasse hinzugefügt“ oder „Button Position angepasst“.

Was soll ich daraus lernen? Was sagen mir diese Nachrichten? All diese Beispiele sind schrecklich. Sie beinhalten kaum relevante Informationen und helfen uns nicht dabei zu verstehen, was wirklich passiert ist.

Wie sieht es also eine Commit-Nachricht aus, die den Namen auch verdient? Welche Informationen gehören darin?, Wie formatiere ich sie? Alles gute Fragen auf die wir jetzt eine Antwort erfahren werden.

Tipps und Tricks für Commit-Nachrichten

Formulierung

Eine der ersten Sachen, dass wir lernten, ist das Commit-Nachrichten im Imperativ geschrieben werden, nicht in der Vergangenheitsform. Das ist sinnvoll, weil die Nachricht das beschreiben soll, was das Commit tut, nicht was früher war. Das passt übrigens auch gut zu den Nachrichten, die git selbst generiert.

Format

Im Laufe der Zeit hat sich ein eindeutiges Format etabliert. Die Nachricht wird in zwei Bereiche aufgeteilt. Ein Betreff mit einer kurzen Bezeichnung, etwa 50 bis 70 Zeichen lang, wo wir deutlich angeben, was sich geändert hat. Dazu eine Beschreibung in den wir detailliert auf die Änderung eingehen. Sie werden mit einer Leerzeile voneinander getrennt. Das machen wir so, weil in vielen Fällen nur die erste Zeile angezeigt wird, der Rest der Nachricht nur bei Bedarf. Das erlaubt uns eine Kurzform der Änderung zu sehen, das ist oftmals ausreichend, um eine grobe Idee zu bekommen. Wenn wir mehr Details brauchen, schauen wir uns die Beschreibungen an.

Inhalt der Beschreibung

In der Beschreibung packen wir alles, was wir brauchen, um zu verstehen, was sich mit dem Commit ändert. Sie sollte so kurz wie möglich sein und so lang wie nötig. Informationen, die dazu gehören, sind:

Was ist das Problem? Was hat uns dazu geführt die Änderungen vorzunehmen? Warum waren sie notwendig? Welche Funktionalität fügen wir hinzu und was ist der Mehrwert? Die Beantwortung diese Fragen zeigt uns das Was und das Warum. Das ist wichtig um den Rahmen zu setzen.

Wie haben wir die Implementierung durchgeführt? Warum haben wir den Weg gewählt? Das ist wichtig. Dank daran: Obwohl es gerade klar ist, warum es so umgesetzt wird, kann es durchaus sein, dass in einigen Wochen es nicht mehr so eindeutig ist, vor allem wenn es jemand anders liest.

Hast du Seiteneffekte entdeckt? Dann solltest du sie erwähnen, um Fehlerquellen aus dem Weg zu gehen.

Gibt es offene Punkte? Auch das sind Informationen, die dazugehören. Am besten legen wir schon mal entsprechende Tickets an, die wir auch verlinken. Dazu erzähle ich euch gleich mehr. Wir stellen klar, dass die Änderung nicht voll abgeschlossen ist. Welche Verbesserungen kommen noch dazu?

Natürlich müssen nicht immer all diese Informationen dabei sein. Das sind halt nur ein paar Tipps und Richtlinien. Auf jeden Fall haben wir damit einen runden Bild, ohne im Code nachzuschauen.

Ich fasse zusammen: In der Beschreibung schreiben wir alles, was wir brauchen, um die Änderung zu verstehen und ggf. Nachzuprüfen.

Das Wichtigste ist im Kopf zu behalten, dass die Informationen in der Commit-Nachricht für Menschen gedacht sind. Das ist das wichtigste Teil.

Wir dürfen natürlich auch weitere Daten angeben, wenn sie von Nutzen sind. Das kann zum Beispiel in Form von Verweise auf externe Systeme geschehen. Eine Verlinkung auf dem Ticket, welche die Änderung zugrunde liegt, ist ein guter Beispiel.

Hinter den Referenzen stecken bestimmte Informationen. Wenn sie wichtig sind, um die Änderung zu verstehen, nehmen wir sie in der Nachricht auf, weil wir nicht wissen können, ob die Menschen, die unsere Nachrichten lesen, Zugang zum externen System haben. Aber, Was macht es für einen Sinn die Referenz einzufügen, wenn wir den Inhalt sowieso in der Nachricht aufnehmen? Mir fallen zwei Gründe ein, um es zu tun.

Erstens. Es ist denkbar, dass die Informationen im Ticket viel detaillierter sind, als das was wir im Commit angeben möchten. Denk daran: so kurz wie möglich … Zweitens. Auch wenn es nicht so ist, kann diese Referenz maschinell ausgewertet werden. Zum Beispiel durch ein Analysetool.

Commit-Größe

Ein weiterer Punkt bringt mich zum Grübeln, und zwar, weil ich das Problem selbst habe. Meine Commits sind manchmal viel zu groß. Aber was bedeutet eigentlich viel zu groß? Na ja, ganz einfach, entweder habe ich mehrere Änderungen auf ein Mal hinzugefügt oder die Änderung war von vorne rein viel zu wuchtig.

Das Erste vermeiden wir, in dem wir darauf achten, dass Anpassungen, die nicht miteinander zu tun haben, in getrennte Commits zu packen. Das bedeutet ein Commit; Eine Änderung. Nicht mehrere Änderungen in ein Commit. Das hilft dabei sie kleiner zu halten.

Das Zweite kann ein vorgelagertes Problem sein. Tickets mit zu viel Inhalt. Das führt dazu, dass viele Anpassungen nötig sind, um das Ticket zu bearbeiten. Dann müssen wir eben das Ticket in Kleinere aufteilen. Kleinere Tickets, die voneinander abgetrennt sind. Damit sind wir das Problem los.

Und was ist, wenn das Ticket nicht geteilt werden kann? Das höre ich öfters, obwohl ich mir nichts immer erklären kann, warum es nicht möglich sein soll. Na ja, egal. Auch dann haben wir die Möglichkeit, nicht alles auf einmal zu committen, sondern die Commits aufzuteilen, so wie wir mit den Anpassungen vorankommen. Heißt, wir machen ein paar Anpassungen und wenn sie eine abgeschlossene kleine Einheit bilden, setzen wir den Commit ab und arbeiten dann weiter.

Um es auf dem Punkt zu bringen, nutze liebe kleinere unabhängige Commits anstatt großere mit verschiedene Abhängigkeiten.

Conventional Commits

Mit all dem, was bis jetzt gesagte wurde, bist du in der Lage Commit-Nachrichten zu schreiben, die inhaltlich top sind.

In meinem Team haben wir noch eins drauf gesetzt und du kannst das auch.

Ich habe vorher erwähnt, dass wir „Conventional Commits“ ausprobiert haben und dabei geblieben sind. Das ist die Next-Level Commit-Nachricht.

Conventional Commits“ ist eine einfache Konvention, welche das Format der Commit-Nachrichten beschreibt. Die Struktur ist sehr ähnlich zu der, die ich vorher erwähnt habe. Erinnert ihr euch daran? Das Teil mit dem zwei Bereichen durch eine Leerzeile getrennt, usw.

Auf „www.conventionalcommits.org“ findest du die Dokumentation dafür, oder schaue dir den passenden Blog-Artikel auf meine Seite an. Dort findest du weitere Details und ein paar Beispiele.

Wie sieht es denn also die Struktur der Commit-Nachricht aus? Also, Sie wird in drei Bereiche unterteilt. Nennen wir sie einfach: Betreffzeile, Beschreibung und Fußnoten. Der Erste ist Pflicht und die andere zwei sind optional, obwohl ich euch empfehle zumindest die Beschreibung zu Nutzen, um die Aussagekraft der Commit-Nachricht zu erhöhen.

Die Betreffzeile fängt mit der Angabe des Änderungstyps an. Es gibt zwei fest definierte Typen: „feat“, abgeleitet von „feature“ für neue Funktionalität und „fix“ für Fehlerkorrekturen. Warum die zwei? Das hängt mit „semver“ und die automatische Vergabe von Versionsnummern zusammen. Weitere Infos darüber findest du unter „semver.org“. Das bedeutet aber nicht, dass du darauf beschränkt bist. Du oder dein Team können sich weitere Typen ausdenken und sie nutzen. Ein Paar Beispiele kann ich dir geben: „docs“ kannst du verwenden, um Änderungen zu markieren, die mit der Dokumentation des Projektes zu tun haben. “Test“ nutzt du, wenn du nur an den Tests geschraubt hast. Es gibt einige Andere, die allgemein genutzt werden. Auf der oben genannte „Conventional Commits“-Seite werden weiter genannt. Ich rate dir, sie auch zu nutzen und nur Neue zu erfinden, wenn du sie wirklich braucht.

Wir sind noch in der Betreffzeile. Als Nächstes kommt der Bereich, immer in runden Klammern. Hier hast du freie Wahl. Gibt an, was für dich Sinn ergibt. Wenn du in einem Team arbeitest, dann ist meistens eine gute Idee, die möglichen Bereiche miteinander zu definieren. Was sollten eigentlich die Bereiche beschreiben? Nutze Wörter, um klar zu machen, welches Teil der Anwendung betroffen ist. Zum Beispiel, wenn du Änderungen an der Konfiguration machst, ist „Configuration“ ein guter Kandidat. Oder wenn du die Kafka-Anbindung vorbereitest, dann nehme einfach „Kafka“. Da gibt es keine feste regeln. Entscheide selbst was für Dich sinnvoll ist.

Der dritte uns letzte Teil der Betreffzeile ist die Bezeichnung. Hier gibst du kurz und prägnant an, um was es geht. Sie wird von Typ und Bereich durch einen Doppelpunkt und ein Leerzeichen getrennt.

Widmen wir uns kurz der Beschreibung an. Sie ist ein beliebig langer Text. Hier kommt alles zum Tragen, was ich vorher über bessere Commit-Nachrichten erzählt habe. Denk daran, Was geändert wird, warum es nötig ist, wie findet die Änderung statt, usw.

Damit wären wir beim dritten Teil der Commit-Nachricht angekommen: die Fußzeilen.

Vor ein paar Minuten habe ich erwähnt, dass externe Referenzen ok sind. Jeder Art von Zusatzinformation kann jetzt angegeben werden. Es muss nur ein bestimmtes Format haben. Na ja, eigentlich gibt es zwei Möglichkeiten. Aber eins nach dem anderen. Jede Fußzeile nimmt eine Zeile platz ein (was für eine Überraschung). Danach gibst du die Informationen ein als „Key-Value-Pair“. Zum Beispiel „Reviewer: Alex“. Du kannst so viele Fußzeilen verwenden, wie du möchtest. Gehe halt sparsam damit um. Denke daran „ so wenig wie möglich, so viel wie nötig“.

Es gibt eine zweite Variante, um die Fußzeile zu formatieren. Diese nutzt du zum Beispiel, um dein Ticket zu verlinken. Das machst du so: „Close #1234“.

Ein Extra gibt es noch dazu. Wenn deine Anpassung dazu führt, dass die öffentliche Schnittstelle deine Anwendung sich ändert, auch „Breaking Change“ genannt, dann willst du das auch in deine Commit-Nachricht deutlich machen. Warum denn das? Na ja, einerseits soll, jeder dem es interessiert darüber informiert werden. Das gehört wohl dazu. Andererseits ist das wichtig, wenn du „semver“ verwendest, um deine Versionsnummern zu vergeben. Das kannst du auf zwei Arten einfliessen lassen:

Die erste Möglichkeit ist ein „Ausrufezeichen“ vor dem „Doppelpunkt“ in der Betreffzeile einzufügen. Du erinnerst dich bestimmt daran, als wir über die Betreffzeile gesprochen haben. Die Bezeichnung wird durch ein „Doppelpunkt“ und ein „Leerzeichen“ von Typ und Bereich getrennt. Und genau vor diesem „Doppelpunkt“ setzt du den „Ausrufezeichen“, wenn „Breaking changes“ vorkommen.

Die zweite Möglichkeit ist eine spezielle Fußnote zu verwenden. Du schreibst dann einfach „BREAKING-CHANGE“, mit „Bindestrich“ getrennt und ganz in Großbuchstaben, gefolgt von einem „Doppelpunkt“, einen „Leerzeichen“ und eine kurze Beschreibung.

Semantic Versioning

Semver ist eine Konvention, um die Versionsnummer einer Anwendung mit einer öffentlichen Schnittstelle zu vergeben. Auf die Webseite https://semver.org/lang/de/ findest du die Spezifikation. Hier erzähle ich dir den Teil, die für uns gerade relevant ist.

Eine Versionsnummer besteht aus drei Zahlen, die mit Punkte getrennt werden, zum Beispiel 3.5.2. Die erste Zahl ist die „Major Version“, die zweite Zahl die „Minor Version“ und die Dritte ist der „Patch Version“. Jeder dieser Zahlen wird eine Bedeutung zugesprochen und, wenn du eine neue Version der Software veröffentlichst, werden sie nach bestimmten Kriterien erhöht:

Die Major Version wird geändert, wenn es Änderungen an der öffentliche Schnittstelle der Anwendung gegeben hat. (Breaking Change)

Die Minor Version wird erhöht, wenn neue Funktionalität dazugekommen ist, welche keine Breaking Changes beinhaltet.

Die Patch Version erhöhst du, wenn Fehler korrigiert wurden.

Das ist eigentlich recht einfach, gehen wir davon aus das wir gerade die Version 3.6.2 haben und wir haben einige Änderungen implementiert und wollen ein neues Release veröffentlichen:

Wenn Breaking Changes vorhanden sind bedeuten, dass du die Major Version erhöhen muss. Das bedeutet, dass die neue Version 4.0.0 lauten wird.

Wenn die Änderungen, Funktionalität hinzugefügt haben, ohne die öffentliche Schnittstelle zu verändern, erhöhst du die Minor Version. Das bedeutet, dass die neue Version 3.7.0 heißen wird.

Wenn wir du nur Bugfixes gemacht hast, dann erhöhst du die Patch Version. Das heißt so viel, wie dass die neue Version die 3.6.3 sein wird.

Auf dieser Art und Weise ist es auf Anhieb klar, welche Änderungen in eine neue Version reingekommen sind. Das ist wichtig damit unsere Verwender wissen, ob sie updaten müssen / sollen und mit welche Schwierigkeiten beim update rechnen sollten. Als Beispiel und aus der Sicht des Verwenders, wenn sich die Major Version geändert hat, dann weißt du, dass es Breaking Changes gibt und das kann ein gefährliches Pflaster sein. Das bedeutet, dass es klug wäre sich vor dem Update schlau, zu machen, um herauszufinden, was alles sich geändert hat, weil es eventuell notwendig ist die eigene Software anzupassen. Ein weiteres Beispiel: Wenn sich die Patch Version geändert hat, dann weiss du, dass Fehler korrigiert werden, also die Wahrscheinlichkeit ist groß, dass du den Patch installieren möchtest.

Und was hat das alles mit Conventional Commits zu tun?

Nun, wie bereits erwähnt, Conventional Commits ermöglichen uns, manche Aktionen zu automatisieren. Ein Beispiel dafür ist die Vergabe von neuen Versionsnummern, wenn wir Semantic Versioning verwenden. Du erinnerst dich bestimmt daran, dass als wir über Conventional Commits gesprochen haben, erwähnt haben, dass am Angang der Betreffzeile der Änderungstyp angegeben wird. Zwei der Änderungstypen, fallen besonders ins Auge: feat und fix. Dank diese beiden, wissen wir ob es sich bei der Änderung, um das Hinzufügen neue Funktionalität handelt oder ob wir lediglich einen Fehler korrigieren. Dank die BREAKING-CHANGE Fußnote, bzw. das Ausrufezeichen im der Betreffzeile, weiß du, ob die öffentliche Schnittstelle verändert worden ist. Mit einem passenden Skript kannst du die Commit Historie, seit dem letzten Release durchforsten und anhand diese Informationen, die Version erhöhen. Eine tolle Sache, nicht wahr?

Last Words ...

Jetzt steht Dir nicht mehr im Wege, um Commit-Nachrichten mit super Qualität zu schreiben. Sie werden Dir und deinem Team helfen die Historie leichter zu verstehen. Als extra Geschenk bekommst du dazu eine Dokumentation des Lebens deines Projektes. Das ist alles nicht zu vernachlässigen, aber es gibt noch mehr. Deine Historie strahlt in ein neues Licht. Du kannst Skripte verwenden, um einen zusätzlichen Mehrwert zu erzielen. Sie können die Historie durchsuchen, um zum Beispiel „Changelogs“ zu generieren. Sie sind auch in der Lage deine Versionsnummervergabe zu automatisieren. Du kannst auch Statistiken über Art und Häufigkeit von Commit-Typen generieren lassen. Wie du siehst: Der Aufwand lohnt sich.