Kapitel ▾ 2. Auflage

8.3 Git anpassen - Git Hooks

Git Hooks

Wie viele andere Versionskontrollsysteme verfügt Git über eine Möglichkeit, benutzerdefinierte Skripte auszuführen, wenn bestimmte wichtige Aktionen stattfinden. Es gibt zwei Gruppen dieser Hooks: clientseitig und serverseitig. Clientseitige Hooks werden durch Operationen wie Committing und Merging ausgelöst, während serverseitige Hooks bei Netzwerkoperationen wie dem Empfangen von gepushten Commits ausgeführt werden. Sie können diese Hooks aus allen möglichen Gründen verwenden.

Installation eines Hooks

Die Hooks werden alle im Unterverzeichnis hooks des Git-Verzeichnisses gespeichert. In den meisten Projekten ist dies .git/hooks. Wenn Sie ein neues Repository mit git init initialisieren, füllt Git das Hooks-Verzeichnis mit einer Reihe von Beispielskripten, von denen viele für sich genommen nützlich sind; sie dokumentieren aber auch die Eingabewerte jedes Skripts. Alle Beispiele sind als Shell-Skripte mit einigen Perl-Anteilen verfasst, aber jedes ordnungsgemäß benannte ausführbare Skript funktioniert einwandfrei – Sie können es in Ruby oder Python oder einer anderen Sprache schreiben, mit der Sie vertraut sind. Wenn Sie die mitgelieferten Hook-Skripte verwenden möchten, müssen Sie sie umbenennen; ihre Dateinamen enden alle mit .sample.

Um ein Hook-Skript zu aktivieren, legen Sie eine Datei im Unterverzeichnis hooks Ihres .git-Verzeichnisses ab, die entsprechend benannt (ohne Erweiterung) und ausführbar ist. Von diesem Zeitpunkt an sollte sie aufgerufen werden. Wir werden die meisten wichtigen Hook-Dateinamen hier behandeln.

Clientseitige Hooks

Es gibt viele clientseitige Hooks. Dieser Abschnitt teilt sie in Committing-Workflow-Hooks, E-Mail-Workflow-Skripte und alles andere auf.

Hinweis

Es ist wichtig zu beachten, dass clientseitige Hooks beim Klonen eines Repositorys nicht kopiert werden. Wenn Ihre Absicht mit diesen Skripten darin besteht, eine Richtlinie durchzusetzen, möchten Sie dies wahrscheinlich auf der Serverseite tun; siehe das Beispiel in Ein Beispiel für eine Git-erzwungene Richtlinie.

Committing-Workflow-Hooks

Die ersten vier Hooks haben mit dem Committing-Prozess zu tun.

Der pre-commit-Hook wird zuerst ausgeführt, noch bevor Sie eine Commit-Nachricht eingeben. Er wird verwendet, um den Snapshot zu inspizieren, der gerade committed werden soll, um zu sehen, ob Sie etwas vergessen haben, um sicherzustellen, dass Tests laufen, oder um alles zu untersuchen, was Sie im Code untersuchen müssen. Ein Nicht-Null-Exit aus diesem Hook bricht den Commit ab, obwohl Sie ihn mit git commit --no-verify umgehen können. Sie können Dinge tun wie die Code-Formatierung prüfen (lint oder etwas Äquivalentes ausführen), auf nachgestellte Leerzeichen prüfen (der Standard-Hook tut genau das) oder die Angemessenheit der Dokumentation für neue Methoden prüfen.

Der prepare-commit-msg-Hook wird ausgeführt, bevor der Editor für die Commit-Nachricht gestartet wird, aber nachdem die Standardnachricht erstellt wurde. Er ermöglicht es Ihnen, die Standardnachricht zu bearbeiten, bevor der Commit-Autor sie sieht. Dieser Hook nimmt einige Parameter entgegen: den Pfad zur Datei, die bisher die Commit-Nachricht enthält, den Typ des Commits und die Commit-SHA-1, falls es sich um einen korrigierten Commit handelt. Dieser Hook ist im Allgemeinen nicht für normale Commits nützlich; stattdessen ist er gut für Commits geeignet, bei denen die Standardnachricht automatisch generiert wird, wie z. B. bei vorlagenbasierten Commit-Nachrichten, Merge-Commits, Squashed-Commits und korrigierten Commits. Sie können ihn in Verbindung mit einer Commit-Vorlage verwenden, um programmgesteuert Informationen einzufügen.

Der commit-msg-Hook nimmt einen Parameter entgegen, der wieder der Pfad zu einer temporären Datei ist, die die vom Entwickler geschriebene Commit-Nachricht enthält. Wenn dieses Skript einen Nicht-Null-Exit hat, bricht Git den Commit-Prozess ab, sodass Sie es verwenden können, um Ihren Projektstatus oder Ihre Commit-Nachricht zu validieren, bevor Sie einen Commit zulassen. Im letzten Abschnitt dieses Kapitels demonstrieren wir die Verwendung dieses Hooks, um zu überprüfen, ob Ihre Commit-Nachricht einem erforderlichen Muster entspricht.

Nachdem der gesamte Commit-Prozess abgeschlossen ist, wird der post-commit-Hook ausgeführt. Er nimmt keine Parameter entgegen, aber Sie können den letzten Commit leicht erhalten, indem Sie git log -1 HEAD ausführen. Im Allgemeinen wird dieses Skript zur Benachrichtigung oder Ähnlichem verwendet.

E-Mail-Workflow-Hooks

Sie können drei clientseitige Hooks für einen E-Mail-basierten Workflow einrichten. Sie werden alle vom Befehl git am aufgerufen. Wenn Sie diesen Befehl in Ihrem Workflow nicht verwenden, können Sie sicher zum nächsten Abschnitt übergehen. Wenn Sie Patches per E-Mail erhalten, die von git format-patch vorbereitet wurden, sind einige davon möglicherweise für Sie hilfreich.

Der erste Hook, der ausgeführt wird, ist applypatch-msg. Er nimmt ein einzelnes Argument entgegen: den Namen der temporären Datei, die die vorgeschlagene Commit-Nachricht enthält. Git bricht den Patch ab, wenn dieses Skript mit einem Nicht-Null-Wert beendet wird. Sie können dies verwenden, um sicherzustellen, dass eine Commit-Nachricht ordnungsgemäß formatiert ist, oder um die Nachricht zu normalisieren, indem Sie das Skript sie an Ort und Stelle bearbeiten lassen.

Der nächste Hook, der beim Anwenden von Patches über git am ausgeführt wird, ist pre-applypatch. Etwas verwirrend wird er *nach* dem Anwenden des Patches, aber *bevor* ein Commit erstellt wird, ausgeführt, sodass Sie ihn zur Inspektion des Snapshots vor dem Commit verwenden können. Mit diesem Skript können Sie Tests ausführen oder den Arbeitsbaum anderweitig inspizieren. Wenn etwas fehlt oder die Tests nicht bestehen, bricht ein Nicht-Null-Exit das git am-Skript ab, ohne den Patch zu committen.

Der letzte Hook, der während einer git am-Operation ausgeführt wird, ist post-applypatch, der nach dem Erstellen des Commits ausgeführt wird. Sie können ihn verwenden, um eine Gruppe oder den Autor des von Ihnen übernommenen Patches zu benachrichtigen. Mit diesem Skript können Sie den Patch-Prozess nicht stoppen.

Andere Client-Hooks

Der pre-rebase-Hook wird ausgeführt, bevor Sie etwas rebasen, und kann den Prozess durch einen Nicht-Null-Exit stoppen. Sie können diesen Hook verwenden, um das Rebasen von Commits zu verbieten, die bereits gepusht wurden. Der von Git installierte Beispiel-pre-rebase-Hook tut dies, obwohl er einige Annahmen trifft, die möglicherweise nicht mit Ihrem Workflow übereinstimmen.

Der post-rewrite-Hook wird von Befehlen ausgeführt, die Commits ersetzen, wie z. B. git commit --amend und git rebase (nicht aber von git filter-branch). Sein einziges Argument ist der Befehl, der den Rewrite ausgelöst hat, und er empfängt eine Liste von Rewrites über stdin. Dieser Hook hat viele der gleichen Anwendungsfälle wie die Hooks post-checkout und post-merge.

Nachdem Sie einen erfolgreichen git checkout ausgeführt haben, wird der post-checkout-Hook ausgeführt; Sie können ihn verwenden, um Ihr Arbeitsverzeichnis ordnungsgemäß für Ihre Projektumgebung einzurichten. Dies kann bedeuten, große Binärdateien zu verschieben, die nicht quellcodeverwaltet werden sollen, Dokumentation automatisch zu generieren oder etwas Ähnliches.

Der post-merge-Hook wird nach einem erfolgreichen merge-Befehl ausgeführt. Sie können ihn verwenden, um Daten im Arbeitsbaum wiederherzustellen, die Git nicht verfolgen kann, z. B. Berechtigungsdaten. Dieser Hook kann ebenfalls die Anwesenheit von Dateien außerhalb der Git-Kontrolle validieren, die Sie möglicherweise kopieren möchten, wenn sich der Arbeitsbaum ändert.

Der pre-push-Hook wird während git push ausgeführt, nachdem die Remote-Refs aktualisiert wurden, aber bevor Objekte übertragen wurden. Er empfängt den Namen und den Speicherort des Remotes als Parameter und eine Liste der zu aktualisierenden Refs über stdin. Sie können ihn verwenden, um eine Reihe von Ref-Updates zu validieren, bevor ein Push stattfindet (ein Exit-Code ungleich Null bricht den Push ab).

Git führt gelegentlich Garbage Collection als Teil seines normalen Betriebs durch, indem es git gc --auto aufruft. Der pre-auto-gc-Hook wird kurz vor der Garbage Collection aufgerufen und kann verwendet werden, um Sie darüber zu informieren, dass dies geschieht, oder um die Sammlung abzubrechen, wenn jetzt kein guter Zeitpunkt ist.

Serverseitige Hooks

Zusätzlich zu den clientseitigen Hooks können Sie als Systemadministrator ein paar wichtige serverseitige Hooks verwenden, um nahezu jede Art von Richtlinie für Ihr Projekt durchzusetzen. Diese Skripte werden vor und nach dem Pushen an den Server ausgeführt. Die Pre-Hooks können jederzeit mit einem Nicht-Null-Wert beendet werden, um den Push abzulehnen und eine Fehlermeldung an den Client zurückzugeben; Sie können eine Push-Richtlinie einrichten, die so komplex ist, wie Sie möchten.

pre-receive

Das erste Skript, das beim Bearbeiten eines Pushes von einem Client ausgeführt wird, ist pre-receive. Es nimmt eine Liste von Referenzen entgegen, die über stdin gepusht werden; wenn es mit einem Nicht-Null-Wert endet, werden keine davon akzeptiert. Sie können diesen Hook verwenden, um Dinge zu tun wie sicherzustellen, dass keine der aktualisierten Referenzen Nicht-Fast-Forward sind, oder um die Zugriffssteuerung für alle Refs und die von ihnen geänderten Dateien mit dem Push durchzuführen.

update

Das Skript update ist dem Skript pre-receive sehr ähnlich, mit dem Unterschied, dass es einmal für jeden Branch ausgeführt wird, den der Pusher zu aktualisieren versucht. Wenn der Pusher versucht, zu mehreren Branches zu pushen, wird pre-receive nur einmal ausgeführt, während update einmal pro Branch ausgeführt wird, zu dem er pusht. Anstatt von stdin zu lesen, nimmt dieses Skript drei Argumente entgegen: den Namen der Referenz (Branch), die SHA-1, auf die sich die Referenz vor dem Push bezog, und die SHA-1, zu der der Benutzer zu pushen versucht. Wenn das Skript update mit einem Nicht-Null-Wert beendet wird, wird nur diese Referenz abgelehnt; andere Referenzen können weiterhin aktualisiert werden.

post-receive

Der Hook post-receive wird ausgeführt, nachdem der gesamte Prozess abgeschlossen ist, und kann verwendet werden, um andere Dienste zu aktualisieren oder Benutzer zu benachrichtigen. Er nimmt dieselben stdin-Daten wie der Hook pre-receive entgegen. Beispiele hierfür sind das Versenden von E-Mails an eine Liste, die Benachrichtigung eines Continuous-Integration-Servers oder die Aktualisierung eines Ticket-Tracking-Systems – Sie können sogar die Commit-Nachrichten parsen, um zu sehen, ob Tickets geöffnet, geändert oder geschlossen werden müssen. Dieses Skript kann den Push-Prozess nicht stoppen, aber der Client trennt die Verbindung erst, nachdem es abgeschlossen ist. Seien Sie also vorsichtig, wenn Sie etwas versuchen, das lange dauern könnte.

Tipp

Wenn Sie ein Skript/Hook schreiben, das andere lesen müssen, bevorzugen Sie die langen Versionen von Befehlszeilen-Flags; sechs Monate später werden Sie uns danken.