Was sind Git hooks?
Git Hooks sind Skripte, die jedes Mal ausgeführt werden, wenn ein bestimmtes Ereignis in Git eintritt. Damit lässt sich das Verhalten von Git nach Belieben erweitern.
Recap: Was ist Git nochmal?
Bevor man Git-Hooks verstehen kann sollte man wissen, was Git eigentlich ist. Git ist eine Open-Source-Software zur Versionskontrolle, die es Entwickler-Teams ermöglicht, gleichzeitig an einer Code-Basis zu arbeiten, ohne gegenseitige Änderungen zu überschreiben. Die Software wurde 2005 von Linus Torvalds entwickelt, der auch der Erfinder von Linux ist. Seither hat Git unzähligen Programmierern und Projektmanagern auf der Welt viele Stunden an Arbeit erspart, die sonst für das Zusammenführen verschiedener Versionen des Codes benötigt worden wären. Noch mehr über diese Software erfahren Sie hier.
Wofür braucht man Git Hooks?
Git Hooks eignen sich besonders für Teams, die nach einheitlichen Entwicklungsstandards und Workflows streben und Prozesse automatisieren möchten. Beispielsweise kann man einen Hook schreiben der dafür sorgt, dass nach jedem Push in die Master Branch eine Benachrichtigung per Email oder Slack versendet wird. Oder man kann einen Hook verfassen, der die Formatierung von Commit-Nachrichten überprüft und den Commit ggf. abbricht.
Im Drupal-Kosmos eignen sich Git Hooks insbesondere zur Überprüfung von Coding-Standards. Drupal ist Open-Source und hat unzählige Maintainer. Um besser und effizienter arbeiten zu können haben sich daher mit der Zeit einheitliche Standards entwickelt die definieren, wie Drupal-Code geschrieben werden sollte. Das fängt bei der Namensgebung von Variablen und Funktionen an und endet bei Zeilenabständen und Einrückungen. Mit einem Hook kann nun vor jedem Commit überprüft werden, ob diese Standards eingehalten werden.
Welche Hooks gibt es?
Hooks liegen im “/.git/hooks” Verzeichnis Ihres Repositories. Voraussetzung dafür ist natürlich, dass Sie in Ihrem Projekt ein git Repository initialisiert haben. Wie der Name des Ordners bereits sagt, liegen hier all Ihre Hooks und standardmäßig gibt es dort bereits einige Beispieldateien. Da die Dateien auf “.sample” enden und nicht ausführbar sind, werden sie von Git ignoriert. Sie geben Ihnen aber schon einen Einblick über die Hooks, die verwendet werden können:
- applypatch-msg.sample
- pre-push.sample
- commit-msg.sample
- pre-rebase.sample
- post-update.sample
- prepare-commit-msg.sample
- pre-applypatch.sample
- update.sample
- pre-commit.sample
Die Namen deuten bereits an, wann das entsprechende Skript ausgeführt wird. Würden wir nun wollen, dass ein Hook angewandt wird, müssten wir die Dateiendung “.sample” entfernen und das Skript per Befehl in der Kommandozeile ausführbar machen:
chmod +x <name des hooks>
Das sind aber nicht alle Hooks, die es gibt. Z.B fehlt der “post-receive” hook, der nach einem “git push” ausgeführt wird und somit gut für Continuous Integration geeignet ist. Eine Liste aller verfügbaren Hooks inkl. Beschreibung finden Sie hier.
Der Scope von Git Hooks
Ein Problem mit Hooks ist, dass sie nicht von Git getrackt werden. Das bedeutet, der “./git/hooks” Ordner kann nicht committed und somit auch nicht zwischen Entwicklern geteilt werden. Das ist problematisch, denn wie bereits oben beschrieben ist der Wert von Hooks im Team-Umfeld am höchsten und es sollte sichergestellt sein, dass alle die gleichen Hooks verwenden. Die einfachste Lösung dafür ist, einen neuen Ordner im Projekt zu erstellen (z.B. “my_project/custom_hooks”). Dieser könnte von Git getrackt werden und die jeweiligen Entwickler können sich die Dateien in den ./git/hooks Ordner kopieren. WIchtig ist dann die transparente Kommunikation wenn Hooks geändert werden. Denn jedes mal, wenn ein Entwickler Änderungen an einem Hook macht, muss die entsprechende Datei erneuts in den /.git/hooks Ordner kopiert werden.
In welcher Programmiersprache schreibt man Git Hooks?
Git Hooks lassen sich in jeder Programmiersprache schreiben. Am häufigsten werden jedoch Shell, Python, Ruby und Perl verwendet. Die Sprache des Skripts wird über die Shebang-Zeile (“#!”) bestimmt. Beispielsweise würde die Shebang-Zeile auf einem Unix basierten System folgendermaßen aussehen, wenn man Python 3 verwenden möchte:
#!/usr/bin/env python3
Python eignet sich besonders für das schreiben von Git Hooks, denn die verschiedenen zur Verfügung stehenden Pakete können dem Entwickler im Vergleich zu z.B. Shell einiges an Arbeit abnehmen.
Anwendungsbeispiel
Heutzutage ist es Projekt-Standard, mit Ticketsystemen zu arbeiten. Um Änderungen im Code zu Tickets “verlinken” zu können macht es Sinn, in den Commit-Nachrichten die entsprechende Ticketnummer zu referenzieren. Dann kann später genau nachvollzogen werden, in welchem Zuge und aus welchem Grund die jeweiligen Änderungen vorgenommen wurden. Der erste Schritt ist natürlich, den Entwicklern zu sagen, das sie immer die Ticketnummer referenzieren sollen. Das schützt aber nicht vor Flüchtigkeitsfehlern. Da kommt “commit-msg hook” ins Spiel. Und so geht’s:
- Navigieren Sie sich in das /.git/hooks Verzeichnis
- Entfernen Sie die “.sample” Dateiendung der commit-msg.sample Datei. Git erkennt diese Datei nun als Hook an.
- Führen Sie den Befehl “chmod +x commit-msg” aus. Dadurch wird die Datei ausführbar.
- Fügen Sie den folgenden Code in die Datei ein (z.B. mit Vim oder einem anderen Text-Editor):
#!/usr/bin/env bash
# Regex to validate in commit message.
commit_regex='(#[0-9]+|merge)'
error_msg="Aborting commit. Your commit message is missing either a ticket number (e.g., #12345) or 'Merge'"
if ! grep -iqE "$commit_regex" "$1"; then
echo "$error_msg" >&2
exit 1
fi
Dieses Skript prüft, ob in Ihrer Commit-Nachricht eine Ticketnummer mit “#” am Anfang oder was Wort “merge” enthalten ist. So etwas wie “Ref #12345 Added new feature” oder “Merge develop branch” wäre also zulässig, “I did something” würde hingegen zu einer Fehlermeldung führen.
Bei Git Hooks ist der Rückgabewert des Skripts entscheidend. Der Rückgabewert 0 wird als Erfolg gewertet und der Git-Prozess weiter ausgeführt. Bei jedem anderen Wert, z.B. 1, wird der Prozess abgebrochen. Daher finden Sie am Ende auch die Zeile “exit 1”, wenn die Commit-Nachricht den Test gegen den regulären Ausdruck nicht besteht.
Zusammenfassung
Git Hooks werden beim Eintreten verschiedener Git-Ereignisse ausgeführt und bieten daher die Möglichkeit, standardisierte Entwicklungsprozesse in Teams zu schaffen. Sie befinden sich im /.git/hooks Ordner des Git Repositories und können in verschiedenen Programmiersprachen geschrieben werden. Aber Achtung: Hooks werden nicht von Hooks getrackt und müssen daher von jedem Entwickler manuell in das Hooks-Verzeichnis kopiert werden, oder aber, man baut sich auch dafür eine Automatisierung.