Engineering

Von Conventional Commits zum Changelog

5 Min. Lesezeit aktualisiert am

Conventional Commits geben einem Changelog drei Dinge geschenkt: den Typ jeder Änderung, den Teil des Systems, den sie betrifft, und ob sie etwas kaputt macht. Mehr geben sie nicht. Formulierung, Gruppierung und Auswahl, also der Changelog selbst, bleiben völlig offen, und eine Pipeline, die etwas anderes vorgibt, liefert ein formatiertes Git-Log aus.

feat(exports): add CSV column selection
fix(auth): reject expired refresh tokens
chore(deps): bump node-pg to 8.11

Drei Commits im Format Conventional Commits. Daraus kann eine Maschine ablesen, dass einer ein Feature ist, einer ein Fix, einer Hausputz, und welchen Teil des Systems jeder betroffen hat. Das ist echt nützlich, und es ist das ganze Versprechen der Konvention: eine Commit-Historie, die von etwas anderem als einem Menschen gelesen werden kann. Der Fehler ist zu denken, das ergäbe schon einen Changelog. Es ergibt das Rohmaterial.

Was gibt die Konvention vor?

Einen Typ, einen optionalen Scope und eine Beschreibung: type(scope): description. Übliche Typen sind feat, fix, chore, docs, refactor, test, perf, build, ci. Zwei Dinge markieren einen Breaking Change: ein ! vor dem Doppelpunkt, oder ein BREAKING CHANGE:-Footer. Werkzeuge richten sich nach feat und fix für Minor- und Patch-Versionssprünge, und nach dem Breaking-Marker für Major.

Der Commit gibtDer Changelog brauchtWer die Lücke füllt
feat / fix / choreAdded / Fixed / internEin Mapping, automatisch
(scope)Eine Gruppierung, die die Leserin erkenntEin Mensch, einmal pro Scope
! oder BREAKING CHANGE:Wer bricht, bis wann, und was zu tun istEin Mensch, jedes Mal
Die Beschreibung, für eine Reviewerin geschriebenDas Ergebnis, für eine Kundin geschriebenEin Mensch, jeder Eintrag
Ein CommitEine Änderung, die viele Commits sein kannSquash-Regeln, oder ein Mensch

Der Marker sagt es dem Werkzeug; er sagt es nicht dem Aufrufer, was Thema von Wie man eine API abkündigt und Was ist ein Breaking Change ist. Es ist eine kleine Spezifikation, und sie zu befolgen lohnt sich auch, wenn man nie etwas daraus generiert, weil sie eine Entscheidung pro Commit erzwingt: Ist das eine Änderung, die Nutzer sehen, oder nicht.

Wo hören Conventional Commits auf?

Sie hören beim Satz auf. Alles, was die Konvention erfasst, ist Metadaten über eine Änderung; die Änderung selbst wird noch im Wortschatz einer Reviewerin beschrieben.

Commit-Nachrichten sind für Reviewerinnen geschrieben. fix(auth): reject expired refresh tokens ist korrekt und sagt einer Kundin nichts. Die Leserin eines Changelogs will “du wirst abgemeldet, wenn eine Sitzung wirklich abgelaufen ist, statt sporadische 401er zu sehen”.

Scopes sind intern. exports, auth, ingest sind Modulnamen. Sie sind stabil, was sie gut zum Gruppieren macht, und bedeutungslos für alle außerhalb der Codebasis.

Eine Änderung sind oft mehrere Commits. Ein über elf Commits gemergtes Feature erzeugt elf Einträge, zehn davon Rauschen, und das Zusammenquetschen, um das zu verbergen, verliert die Review-Historie.

chore ist ein Auffangbecken, keine Kategorie. Abhängigkeits-Updates, CI-Änderungen und Umbenennungen landen alle dort, und manche davon zählen für Nutzer, die meisten nicht.

Also: Die Konvention gibt Typ, Scope und Breaking-Status geschenkt und lässt Formulierung, Gruppierung und Auswahl völlig offen. Diese drei sind der Changelog. Wem gehört ein Changelog-Eintrag wirklich behandelt, wer diese Formulierung, Gruppierung und Auswahl übernehmen sollte, da die Konvention selbst keine Meinung dazu hat.

Wie erzeugt man einen Changelog aus Conventional Commits?

In zwei Schichten, und die zweite muss verpflichtend sein.

Schicht eins, automatisch. Beim Merge einen Entwurfseintrag aus dem Commit ableiten: Typ auf einen Changelog-Typ gemappt (feat auf Added, fix auf Fixed, ein Breaking-Marker auf Changed plus Flag), Scope als Metadaten statt als Text behalten, Link zum PR. In den Unreleased-Abschnitt einordnen, den Keep a Changelog verlangt.

Schicht zwei, menschlich, und verpflichtend. Bevor ein Release rausgeht, bekommt jeder Entwurfseintrag entweder eine einzeilige Umformulierung im Wortschatz der Nutzerin, oder wird als intern markiert und aus der öffentlichen Ansicht entfernt. Das ist der Schritt, den Leute überspringen wollen, und ihn zu überspringen erzeugt genau die Changelogs, die wie ein Diff lesen.

Das wichtige Design-Detail ist, dass Schicht zwei in der Pipeline nicht optional ist. Kann ein Release mit unbearbeiteten Entwürfen geschnitten werden, wird es das, in der Woche, in der alle beschäftigt sind. Welche Schritte der Maschine gehören und welche dem Menschen, ist der ganze Inhalt von Changelog-Automatisierung.

Das Release zu schneiden ist auch der Moment, in dem ein Git-Tag, ein Release und dieser Changelog-Eintrag entweder zusammenpassen oder anfangen auseinanderzudriften; Git-Tags, Releases und dein Changelog zeigt, wie man die drei synchron hält.

Drei Fallen

Squash-Merges fressen die Footer. Wenn eure Plattform mit dem PR-Titel als Nachricht zusammenquetscht, verschwindet der BREAKING CHANGE:-Footer eines Commits aus diesem Branch, und eure Werkzeuge sehen den Breaking Change still nicht mehr. Prüft, was eure Squash-Vorlage tatsächlich behält.

Revert-Commits erzeugen Phantomeinträge. Ein fix, der am nächsten Tag zurückgenommen wird, erzeugt einen Eintrag für etwas, das nie ausgeliefert wurde, es sei denn, die Ableitung gleicht Reverts ab. Die meisten Werkzeuge tun das nicht.

Versionssprung und Changelog geraten außer Takt. Wird die Version aus Commits berechnet und der Changelog danach von Hand geschrieben, driften sie innerhalb von etwa zwei Releases auseinander. Berechnet beides im selben Durchgang oder akzeptiert, dass eines davon falsch ist.

Wenn du den mechanischen Teil ohne Pipeline willst

Unser Changelog-Generator macht den Ableitungsschritt im Browser: Commits einfügen, gruppierte, typisierte Einträge raus. Er ist bewusst deterministisch und komplett clientseitig, sodass die eingefügten Commits nie deinen Rechner verlassen, was zählt, wenn die Nachrichten aus einem privaten Repo stammen. Er macht die Sammel-Hälfte ehrlich und versucht sich nicht an Schicht zwei, weil Schicht zwei eine Ermessensfrage ist und ein Werkzeug, das das vortäuscht, genau den Changelog erzeugt, gegen den dieser Artikel argumentiert.

Für die Pipeline-Version deckt Changelog-Tools ab, was es gibt.

Die Zusammenfassung

Conventional Commits beantworten “was für eine Art Änderung ist das” zuverlässig und günstig. Sie beantworten nicht “was sollen wir den Leuten sagen”, und keine Menge Werkzeug oben auf der Commit-Nachricht wird das tun, weil die Information nie in der Commit-Nachricht war. Plant die Umformulierung ein.

FAQ

Erzeugen Conventional Commits automatisch einen Changelog? Sie erzeugen automatisch einen Entwurf: typisierte, mit Scope versehene, verlinkte Einträge. Die Formulierung für eine Kundin, die Gruppierung und die Entscheidung, was wegfällt, braucht immer noch einen Menschen, und eine Pipeline, die diesen Schritt überspringt, veröffentlicht Commit-Nachrichten.

Welche Conventional-Commit-Typen erscheinen in einem Changelog? feat und fix immer, als Added und Fixed. perf meist, als Changed. chore, docs, refactor, test, build und ci sind standardmäßig intern und erscheinen nur, wenn ein Mensch einen davon befördert.

Wie markieren Conventional Commits einen Breaking Change? Ein ! nach Typ oder Scope (feat(api)!: ...), oder ein BREAKING CHANGE:-Footer im Commit-Body. Beides geht verloren, wenn ein Squash-Merge nur den PR-Titel behält.

Braucht man Conventional Commits, um einen Changelog zu automatisieren? Nein. PR-Labels, PR-Vorlagen und Issue-Links tragen dieselben Metadaten für Teams, die per Pull Request mergen. Conventional Commits sind die günstigste Option, wenn die Änderungseinheit der Commit ist.


Die technischen Aussagen in diesem Artikel wurden nicht unabhängig geprüft. Wenn etwas nicht stimmt, sagen Sie es uns, und wir korrigieren es.

Mehr bei changeloop: Changelog-Generator, Changelog-Tools im Vergleich

changeloop
Das Team hinter einem Changelog, das den Kreis schließt. Ihre Nutzer fragen, Ihr Team liefert, und wer gefragt hat, erfährt davon.