Git Hook zur Simulation von Revisionsnummern beim Commit

Mittlerweile führt kaum ein Weg am Einsatz von git als Versionsverwaltungssystem vorbei. Jedoch gibt es manch geliebte Gewohnheit, die beim Umstieg von Subversion auf Git mitunter vermisst wird. Ein Beispiel sind die fortlaufenden Revisionsnummern, die zum einen leichter zu lesen sind als die von Git produzierten Hash-Werte, und zum anderen auch zur Ermittlung von Versionsunterschieden (aka Diffs) innerhalb (halb-)automatisierter Prozesse verwendet werden können.

Ein konkretes Beispiel zeigte sich bei der Migration von Subversion auf Git im aktuellen Projekt. Da es während der Entwicklung immer wieder zu Änderungen im Datenbank-Schema kommt, wurde ein Skript erstellt, was anhand der Revisionsnummer von Subversion prüft, ob Schemaänderungen vorhanden sind, und wenn ja, diese auf die Datenbank anwendet. Eine simple, aber effektive Art, vergleichbar mit der Migration aus Frameworks wie Ruby on Rails. Diese Lösung sollte möglichst beibehalten werden, um Kompatibilität mit den vorhandenen Deploy-Skripten zu erhalten.

Eine einfache Möglichkeit, für den jeweils aktuellen Branch eine Revisionsnummer zu ermitteln ist: Durchzählen der Commits. Klingt genauso simpel wie es ist. Schnell erledigt mittels folgenden Kommandos:

git rev-list HEAD | wc -l

Damit wird die Anzahl der jeweils aktuellen Commits ermittelt. Der nächste Schritt besteht daraus, die beim Commit erzeugte neue Revisionsnummer automatisiert bestimmten Dateien hinzuzufügen. Von CVS und Subversion bekannt ist die Keyword Substitution. Beim Auftreten bestimmter Keywords im Quelltext, etwa $Revision$ ersetzt das Versionsverwaltungssystem diesen String durch die jeweils generierte Angabe.
Darauf basiert wiederum das Deploy-Skript, was aufgrund dieser Revision die bereits durchgeführten Schemaänderungen ermittelt und neue Änderungen ausführt.

Bei Git gibt es diese Keyword Substitution nicht, bzw. vom Einsatz wird abgeraten. Die Gründe sind legitim und nachvollziehbar, jedoch basieren die bestehenden Prozesse darauf, und in diesem Fall war die pragmatische Entscheidung für “never change a running system” leicht. Eine Lösung musste her.

Diese besteht im folgenden Skript bzw. Hook:

Zur Einrichtung muss das Skript unter dem Namen “pre-commit” ins Verzeichnis .git/hooks/ gestellt und ausführbar gemacht werden. Die CLI-Variante sollte unter dem angegebenen Verzeichnis enthalten sein.

Zwar gibt es mittlerweile viel Dokumentation über Git, aber die Hinweise zu Hooks sind teilweise noch spärlich und nicht unbedingt leicht verständlich. Eine Ausnahme stellt die Seite Arbeiten mit Git Hooks dar. Das hier dargestellte Skript basiert auf einem darin angegebenen Beispiel, an dieser Stelle vielen Dank an den Autor Alexander Meindl.

Ziel: Ersetzen aller $Revision$ Vorkommen durch die beim Commit erzeugte Revisionsnummer in Dateien mit der Endung *.sql.

Vorgehen:

  • Zunächst wird die Nummer, d.h. Anzahl bisheriger Commits ermittelt, um eins hochgezählt (da neuer Commit relevant) und in $newRevision gespeichert.
  • Danach werden die Dateinamen der durch das Kommando git add hinzugefügten und vor dem Commit befindlichen Files in einem Array gespeichert.
  • Dieses Array wird iteriert, dabei erfolgt der Vergleich, ob die Endung *.sql ist. Weitere erlaubte Endungen können in $needle definiert werden.
  • Falls es sich um eine *.sql-Datei handelt, wird der Inhalt eingelesen, $Revision$ durch die zuvor ermittelte neue Revisionsnummer ersetzt.
  • Zum Schluss wird die bearbeitete Datei erneut mit git add hinzugefügt, da git ansonsten die Datei im Zustand vor der Ersetzung committen würde, was einen weiteren git add … git commit Durchlauf notwendig werden ließe. Da der Hook pre-commit jedoch, wie der Name es besagt, vor dem Committen ausgeführt wird, sorgt das neuerliche Hinzufügen mit git add dafür, dass der Commit die geänderte Datei erfasst.

Für die konkrete Anwendung stellt dieses Skript somit eine geeignete Lösung dar.

Update 04.06.2013: Das Skript ermittelt nun zuvor das Root-Verzeichnis des jeweiligen git-Arbeitsverzeichnisses (bzw. Repositories), so dass es aus jedem beliebigen Verzeichnis ausgeführt werden kann.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Tags:
Kategorie: Programmierung