Automatisierung per Versionsverwaltung – ein Fallbeispiel Git-Commit-Nachrichten kreativ nutzen

Von Mirco Lang

Anbieter zum Thema

Commit-Messages können mehr als nur informativ sein: Ob Quick-and-Dirty-Abkürzung oder Hilfestellung für Einsteiger, es braucht nur ein wenig Kreativität und Hooks.

Dieses Skript speichert den Hash des letzten Commits, so dass dieser weiterverarbeitet werden kann.
Dieses Skript speichert den Hash des letzten Commits, so dass dieser weiterverarbeitet werden kann.
(Bild: Lang)

Gits Commit-Nachrichten sind unverzichtbar, um die Arbeit in einem Repository nachvollziehen zu können – wenn sie denn sinnvoll geschrieben sind. Wie sich die Messages konsistent und aussagekräftig gestalten lassen, haben wir Ihnen kürzlich im Beitrag zu Git Conventional Commits gezeigt.

Auch die zweite Git-Technik, um die es hier geht, haben wir schon mal in Gänze vorgestellt, nämlich Git Hooks. Hooks werden zu unterschiedlichen Punkten im Git-Workflow ausgeführt und können im Grunde beliebigen Code enthalten. Im Hooks-Artikel wird dazu auch ein kurzes Beispiel genannt: Durchsetzung einer Commit-Nachrichten-Richtlinie wie der Git-Conventional-Commits-Konvention (für dies es fertige Tools gibt, die ebenfalls auf Hooks setzen).

Fallbeispiel

Im Folgenden zeigen wir ein einfaches, konkretes Beispiel: In einem Dokumentationsprojekt werden via Git mehrere Manual-Versionen für verschiedene Software-Versionen und -Editionen gepflegt, in Form jeweils eigener Branches. Bisweilen sind Aktualisierungen oder Ergänzungen nicht nur für eine Version oder Edition relevant, sondern für mehrere Kombinationen.

Änderungen müssen also in mehrere Branches übernommen werden. In der Entwicklung würde man das vielleicht als Feature-Branch aufziehen und dann je nach Bedarf per Merge oder Rebase mit anderen Branches zusammenführen. Wenn es aber nur um kurze Hinweise oder ein paar Screenshots geht, ist das recht viel Aufwand.

Zudem arbeiten nicht nur Git-Profis in Git, sondern auch Menschen, die ihr Leben lang mit drei git-Befehlen auskommen – pull, commit und push. Es sollte also eine einfache Lösung sein – dafür gibt es das Cherry-Picking.

Der Workflow ist im Grunde „simpel“ (je nach Perspektive): Auf einem Branch committen, zum anderen Branch wechseln, den Commit per cherry-pick rüberziehen, pushen, zurück zum ursprünglichen Branch. Aus Entwickler-Perspektive könnte es wohl kaum simpler sein Aber wenn Webseiten und sonstige „Menschentexte“ quasi selbstverständlich über Dienste wie GitHub zusammen mit der Software selbst verwaltet werden, werden eben auch Autoren damit konfrontiert – und aus der Perspektive ist die Hantiererei mit Hashes auf der Kommandozeile nicht wirklich einfach.

Dabei geht es durchaus einfach und ohne die drei Basisbefehle zu verlassen: Warum nicht einfach in der Commit-Nachricht den Wunsch angeben, dass dieser Commit auch noch in drei anderen Branches übernommen werden soll? Mit Git lässt sich nicht direkt in mehrere Branches committen, aber das Cherry-Picking lässt sich über beliebig gestaltbare Anweisungen in Commit-Nachrichten automatisieren.

Statt also jeden einzelnen Branch manuell via …

git checkout version_2.0
git cherry-pick abc1230z
git push
git checkout main

… zu aktualisieren, genügt dann der ursprüngliche Commit im main-Branch:

git commit -am „branch:version_2.0 … irgendein Text ...“

In vielen Fällen dürfte dieses Vorgehen einfacher sein, aber bei zehn betroffenen Branches auch schneller! Insofern wäre diese Variante vielleicht auch für fortgeschrittene Nutzer interessant. Ein Ausweg aus etwaigen Merge-Höllen ist dies freilich nicht.

Umsetzung

Diese Idee zu implementieren ist grundsätzlich furchtbar simpel, unsere Demo kommt mit insgesamt 15 Zeilen Code aus, berücksichtigt aber nur einen weiteren Branch. Für den produktiven Einsatz müsste etwas mehr Aufwand in die Auswertung der Commit-Nachricht gesteckt werden, um mehrere Branches, Rechtschreibfehler und dergleichen zu berücksichtigen.

Die Git-Hooks finden Sie standardmäßig unter „.git/hooks“, allerdings handelt es sich um lokale Hooks, die entsprechend nicht synchronisiert werden. Da derlei Hooks aber tendenziell geteilt werden sollen, hier ein kleiner Extraschritt:

Legen Sie im Repository einen Ordner „.git-hooks“ an und aktualisieren Sie dann die Git-Konfiguration, um diesen Ordner als Hooks-Ordner festzulegen:

git config core.hooksPath .git-hooks/

Nun benötigen Sie darin ein Hook-Skript namens „commit-msg“:

#!/bin/bash# Prüfen, ob „branch“ in der Commit-Nachricht ($1) vorhanden ist
if $(grep -q 'branch' $1); then
  echo Nachricht enthält branch – okay.
  exit
else
  echo -e '\nKein branch in der Nachricht– Commit wird abgebrochen.\n' && exit 1
fi

Dieses Minimalskript prüft also beim Absenden von „git commit“, ob die Nachricht („$1“) „branch“ enthält – falls ja, wird der Commit ausgeführt, ansonsten abgebrochen. In der Praxis müsste hier wie erwähnt ausführlicher geprüft werden. Folgende Commit-Nachricht würde den Test bestehen:

Jetzt Newsletter abonnieren

Täglich die wichtigsten Infos zu Softwareentwicklung und DevOps

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung
git commit -am „branch:version_3 Der normale Text ...“

Wenn die Bedingungen des obigen Skripts erfüllt werden, läuft der Commit durch und der Hook „post-commit“ wird ausgeführt – und diesem steht nun auch der Commit-Hash zur Verfügung. Legen Sie also ein zweites Skript „post-commit“ im Ordner „.git-hooks“ an:

#!/bin/bashif [ $(git log -1 HEAD | sed -n 's/.*branch:\(.*\)\b.*/\1/p') ]; then
  pickbranch=$(git log -1 HEAD | sed -n 's/.*branch:\(.*\)\b.*/\1/p')
  pickcommit=$(git rev-parse HEAD)
  git checkout $pickbranch
  git cherry-pick $pickcommit
  git push
  git checkout main
else
  echo -e '\nKeine Branch-Angabe zum Picken.\n'
fi

In der if-Zeile wird geprüft, ob im letzten Commit eine Branch-Information hinter „branch:“ steht – falls nicht, wird abgebrochen. Falls doch, so wird was auch immer hinter „branch:“ steht bis zum nächsten Wort-Trennzeichen (über sed via „\b“ zu adressieren) in der Variablen „pickbranch“ gespeichert – dem gewünschten Ziel-Branch.

Anschließend wird in der Variablen „pickcommit“ der Commit-Hash des letzten Commits gespeichert. Und mit diesen beiden Variablen werden dann die normalen Git-Kommandos aus dem manuellen Workflow aufgerufen. Hier also nochmal der Commit:

git commit -am „branch:version_3 Der normale Text …“

Der „commit-msg“-Hook wird diesen akzeptieren, weil „branch:“ vorkommt. Der „post-commit“-Hook führt ganz konkret aus:

git checkout version_3
git cherry-pick abc1230z
git push
git checkout main

Natürlich sind die Skripte soweit nicht reif für den produktiven Einsatz in professionellen Umgebungen mit mehreren Nutzern. Doch als persönliche Arbeitshilfe haben sie schon in diesem Status ihren Reiz. Es gibt auch fertige Tools zum Verifizieren von Commit-Nachrichten via Hook, beispielsweise für die Conventional-Commits-Konvention. Interessant wäre hier auch Pre-Commit, ein Framework zum Verwalten von Git-Hooks.

Das obige Fallbeispiel soll vor allem demonstrieren, was mit Git-Commit-Nachrichten in Kombination mit Git-Hooks ganz konkret möglich ist. Technische Grundlage könnte Pre-Commit sein, inhaltliche Vorlage die Conventional Commits – damit ließe sich eine stabile Automatisierung über Commit-Nachrichten realisieren.

Möglichkeiten gibt es hier viele: Vom Anstoßen von Build-Prozessen durch das Schlagwort „release“ bis hin zu Backups über „backup“ und so weiter. Oder auch ganz nahe liegende Dinge: Warum nicht besonders wichtige Commits für Management-Reports kennzeichnen? Das Kommandozeilentool für die Conventional Commits bringt das im Grunde sogar schon mit sich: Aus den sauber formatierten Commit-Messages produziert dieses einen ebenso sauber formatierten Changelog!

Ob Vereinfachung, Batch-Verarbeitung oder gar komplette Automatisierung – das Duo aus Nachricht und Hook ist schon sehr reizvoll.

(ID:48628805)