
Conventional Commits: Das fehlende Bindeglied zwischen Ihren Commits und Ihrer Versionsnummer
- VersionDude
- guides
- 7 Min. Lesezeit
Eine feste Form für Commit-Nachrichten, die fix mit PATCH und feat mit MINOR verknüpft, sodass sich die nächste Versionsnummer aus dem Log ergibt. Die beiden Schreibweisen für Breaking Changes, und was die Spezifikation bewusst nicht leistet.
Wenn Sie Ihre Releases bereits nach Semantic Versioning nummerieren und ein Changelog pflegen, klafft zwischen beidem eine Lücke, die die meisten Teams von Hand schließen: Jemand muss die Commits seit dem letzten Release durchlesen und entscheiden, ob die nächste Version ein Patch, ein Minor oder ein Major wird. Conventional Commits ist eine Spezifikation, die diese Lücke schließt, indem sie die Antwort in die Commit-Nachricht selbst legt, und zwar in dem Moment, in dem die Änderung entsteht.
Der Aufbau der Nachricht

Die Spezifikation legt eine feste Form für die erste Zeile fest, mit einem optionalen Body und Footern darunter. Ausgeschrieben lautet die Struktur: Typ, dann ein optionaler scope in Klammern, dann ein Doppelpunkt und ein Leerzeichen, dann eine kurze Beschreibung. Eine Leerzeile trennt den Body ab, und weitere Leerzeilen trennen etwaige Footer.
Ein Bugfix im Parser wird damit zu fix(parser): handle empty attribute values, und eine neue Fähigkeit zu feat(api): add pagination to the search endpoint. Der scope ist optional, und die Beschreibung ist eine Zusammenfassung und kein Aufsatz. Alles Längere gehört in den Body darunter.
Wie die Typen auf SemVer abbilden
Der Grund für die feste Form liegt darin, was die Typen ermöglichen. Die Spezifikation verknüpft zwei von ihnen unmittelbar mit Semantic Versioning: Ein fix-Commit korrespondiert mit PATCH, und ein feat-Commit korrespondiert mit MINOR. Ein Commit, der eine brechende Änderung an der API einführt, korrespondiert mit MAJOR.
- Struktur: Typ, optionaler scope in Klammern, dann Doppelpunkt und Leerzeichen, dann die Beschreibung. Body und Footer stehen darunter, jeweils durch eine Leerzeile getrennt.
- fix korrespondiert mit PATCH in Semantic Versioning, und feat korrespondiert mit MINOR.
- Eine brechende Änderung an der API korrespondiert mit MAJOR und wird entweder mit einem BREAKING CHANGE:-Footer oder mit einem Ausrufezeichen vor dem Doppelpunkt gekennzeichnet.
- Wird das Ausrufezeichen verwendet, darf der BREAKING CHANGE:-Footer entfallen, und die Beschreibung deckt ihn ab.
- Die Spezifikation ist eine Nachrichtenkonvention, kein Release-Werkzeug: Sie korrespondiert mit den SemVer-Stufen, berechnet aber von sich aus nichts.
Genau diese Zuordnung erlaubt es Werkzeugen, die nächste Versionsnummer zu ermitteln, ohne dass ein Mensch das Log liest. Sie verschiebt die Entscheidung außerdem zu der Person, die sie am besten treffen kann, nämlich zu derjenigen, die die Änderung geschrieben hat, in dem Moment, in dem sie sie geschrieben hat, statt zu einem Release-Manager, der Wochen später die ursprüngliche Absicht rekonstruiert.
Zwei Wege, einen Breaking Change zu markieren
Für Breaking Changes gibt es zwei anerkannte Schreibweisen, und beide zu kennen ist wichtig, weil Ihnen beide in echten Repositories begegnen werden. Die erste ist ein Footer, der mit BREAKING CHANGE: beginnt, gefolgt von einer Beschreibung. Die zweite ist ein Ausrufezeichen unmittelbar vor dem Doppelpunkt, wie in feat(api)!: drop support for v1 tokens.
Die beiden sind nicht bloß stilistische Alternativen. Die Spezifikation hält fest: Wird das Ausrufezeichen verwendet, darf der BREAKING CHANGE:-Footer entfallen, und die Commit-Beschreibung selbst dient dann als Beschreibung der brechenden Änderung. Mit anderen Worten ist die Kurzform für sich genommen vollständig, weshalb man sie in der Praxis am häufigsten sieht.
Was die Spezifikation nicht leistet
Es lohnt sich, genau zu benennen, was diese Spezifikation leistet und was nicht. Sie ist eine Konvention zum Schreiben von Nachrichten, kein Release-Werkzeug. Die Spezifikation sagt, dass die Typen mit den SemVer-Stufen korrespondieren; sie berechnet selbst keine Versionen, erzeugt keine Changelogs und veröffentlicht nichts. Das sind Aufgaben für Werkzeuge, die die Konvention auslesen, und welche das sind, ist eine eigene Entscheidung.
Der Nutzen, der auch ganz ohne Werkzeuge bestehen bleibt, wird von Teams unterschätzt. Für jeden Commit einen Typ zu verlangen, erzwingt eine kleine Beurteilung im Moment des Schreibens: Ist das ein Fix, ein Feature, oder etwas, das einem Konsumenten die Grundlage entzieht? Ein Team, das diese Frage elfhundert Mal im Jahr beantwortet, hat ein weit genaueres Gespür für die eigene Release-Oberfläche als eines, das sie viermal im Jahr bei der Vorbereitung eines Releases beantwortet.
Einfuehrung ohne Zeremonie
Die Einführung braucht kein Zeremoniell. Die Konvention gilt ab dem Commit, ab dem Sie sie anwenden, und ein Repository mit gemischter Historie funktioniert einwandfrei, denn die Werkzeuge, die die Konvention auslesen, ignorieren schlicht, was sie nicht parsen können. An einem Montag anzufangen, ohne Migration und ohne umgeschriebene Historie, ist ein völlig legitimer Weg der Einführung.
Wenn Sie lieber ein Sicherheitsnetz als reine Disziplin möchten, genügt ein Commit-Message-Hook, der eine nicht konforme erste Zeile zurückweist, und das kostet eine Konfigurationsdatei. Beginnen Sie aber mit der Konvention selbst. Die Spezifikation ist kurz, die beiden SemVer-Entsprechungen sind der Teil, der sich auszahlt, und die Schreibweise mit Ausrufezeichen ist das Detail, das die meisten beim ersten Lesen übersehen.



Der Nutzen, der auch ganz ohne Werkzeuge bestehen bleibt, wird von Teams unterschätzt. Für jeden Commit einen Typ zu verlangen, erzwingt eine kleine Beurteilung im Moment des Schreibens: Ist das ein Fix, ein Feature, oder etwas, das einem Konsumenten die Grundlage entzieht? Ein Team, das diese Frage elfhundert Mal im Jahr beantwortet, hat ein weit genaueres Gespür für die eigene Release-Oberfläche als eines, das sie viermal im Jahr bei der Vorbereitung eines Releases beantwortet.