Git Hooks
Git Hooks erklärt: Skripte, die automatisch im Git-Lebenszyklus laufen, um Lint, Tests und Validierungen durchzuführen. Mit pre-commit-Beispiel.
Was sind Git Hooks
Git Hooks sind Skripte, die Git automatisch ausführt, wenn bestimmte Ereignisse eintreten – Commits, Merges, Pushes und mehr. Sie ermöglichen es, benutzerdefinierte Aktionen in den Git-Lebenszyklus einzubinden: einen Linter vor jedem Commit ausführen, das Format einer Commit-Nachricht prüfen oder einen Push blockieren, wenn die Tests fehlschlagen. Hooks sind das Mittel, mit dem Teams lokal Qualitätsgrenzen durchsetzen, bevor fehlerhafter Code die Maschine verlässt.
Diese Seite behandelt, wo Hooks gespeichert werden, den Unterschied zwischen client- und serverseitigen Hooks, die nützlichsten Hooks mit funktionierenden Beispielen, wie ein Hook eine Operation abbricht, wie man einen Hook umgeht und wie Hooks im Team geteilt werden können.
Wo Hooks gespeichert werden
Jedes Repository verfügt über ein .git/hooks-Verzeichnis mit Beispielskripten und der Endung .sample. Um einen Hook zu aktivieren, muss eine ausführbare Datei mit dem exakten Namen des Hooks und ohne Erweiterung erstellt werden:
ls .git/hooks
# pre-commit.sample commit-msg.sample pre-push.sample ...Die Endung .sample entfernen (oder die Datei neu anlegen) und sie ausführbar machen:
chmod +x .git/hooks/pre-commitEin Hook kann in jeder Sprache geschrieben werden, solange die Datei ausführbar ist und mit einer passenden Shebang-Zeile beginnt (#!/bin/sh, #!/usr/bin/env python3, #!/usr/bin/env node usw.). Git prüft lediglich, ob die Datei exakt nach einem bekannten Hook benannt ist, ausführbar ist und einen Exit-Code zurückgibt.
Clientseitige vs. serverseitige Hooks
- Clientseitige Hooks laufen auf dem eigenen Rechner bei lokalen Operationen wie Commits und Pushes. Sie eignen sich besonders für Linting und Tests.
- Serverseitige Hooks (wie
pre-receiveundpost-receive) laufen auf dem Remote-Repository, wenn es einen Push empfängt – nützlich, um Richtlinien zentral durchzusetzen.
Die am häufigsten verwendeten Hooks sind clientseitig:
| Hook | Auslöser | Typischer Einsatz |
|---|---|---|
pre-commit | Bevor ein Commit erstellt wird | Lint und Test der gestagten Dateien; Abbruch bei Fehler. |
prepare-commit-msg | Bevor der Nachrichteneditor geöffnet wird | Template oder Ticket-Nummer einfügen. |
commit-msg | Nachdem die Nachricht geschrieben wurde | Nachrichten-Konvention durchsetzen. |
post-commit | Nachdem ein Commit abgeschlossen wurde | Benachrichtigung senden; kein Einfluss auf den Commit. |
pre-push | Bevor ein Push gesendet wird | Die gesamte Testsuite als letzte Prüfung ausführen. |
Wie ein Hook eine Operation abbricht
Der gesamte Steuerungsmechanismus basiert auf dem Exit-Code. Für einen „pre-"-Hook (pre-commit, pre-push, commit-msg, …):
- Exit
0→ Der Hook hat die Operation genehmigt, und Git fährt fort. - Exit ungleich null → Git bricht die Operation ab. Der Commit wird nicht erstellt oder der Push nicht gesendet.
„Post-"-Hooks (post-commit, post-merge, …) laufen nach dem Abschluss der Aktion, daher wird ihr Exit-Code ignoriert – sie können nichts rückgängig machen. Sie sollten für Benachrichtigungen, nicht für Validierungen verwendet werden.
Ein pre-commit-Beispiel
Dieser pre-commit-Hook führt den Projekt-Linter aus und blockiert den Commit, wenn Probleme gefunden werden. Da sh durch set -e beim fehlgeschlagenen Befehl abbricht, ist keine zusätzliche Prüfung von $? erforderlich:
#!/bin/sh
set -e
echo "Running lint..."
npm run lintWenn npm run lint mit einem Nicht-Null-Wert beendet wird, gibt set -e diesen Code weiter und der Commit wird abgebrochen. Falls eine benutzerdefinierte Meldung bevorzugt wird, kann das Ergebnis explizit geprüft werden:
#!/bin/sh
if ! npm run lint; then
echo "Lint failed — commit aborted. Fix the issues and try again."
exit 1
fiDiese Datei als .git/hooks/pre-commit speichern und chmod +x .git/hooks/pre-commit ausführen.
Ein commit-msg-Beispiel
Der commit-msg-Hook erhält ein Argument: den Pfad zu einer temporären Datei, die die vorgeschlagene Nachricht enthält. Diese Datei lesen, validieren und bei einem Nicht-Null-Exit ablehnen. Dieses Beispiel setzt einen Conventional Commits-Stil-Präfix durch:
#!/bin/sh
# $1 is the path to the file containing the commit message
message=$(head -n1 "$1")
pattern='^(feat|fix|docs|style|refactor|test|chore): .+'
if ! echo "$message" | grep -Eq "$pattern"; then
echo "Commit message must start with feat:, fix:, docs:, etc."
exit 1
fiEinen Hook umgehen
Ein Hook ist ein Sicherheitsnetz, keine Wand. Wenn es wirklich nötig ist, die pre-commit- und commit-msg-Hooks für eine Operation zu überspringen, kann --no-verify verwendet werden:
git commit --no-verify -m "WIP: skip checks"
git push --no-verifyDies sollte sparsam eingesetzt werden – das Umgehen des Linters ist der Weg, auf dem fehlerhafter Code in die Historie gelangt.
Hooks im Team teilen
Da .git/hooks nicht versioniert wird, werden Hooks nicht beim Klonen übertragen. Teams lösen dies, indem Hooks in einem versionierten Verzeichnis gespeichert und Git darauf hingewiesen wird:
git config core.hooksPath .githooksNun sucht Git im versionierten .githooks/-Verzeichnis statt in .git/hooks. Die Skripte dort einchecken, ausführbar machen, und jedes Teammitglied erhält sie, nachdem der gleiche git config-Befehl ausgeführt wurde (oder ein Setup-Skript dies übernimmt). Weitere Informationen zum Speichern von Repository-spezifischen Einstellungen finden sich unter Git config.
Tools wie Husky automatisieren genau dies für JavaScript-Projekte und richten gemeinsame Hooks bei der Installation ein. Für Richtlinien, die niemand mit --no-verify umgehen darf, sollten serverseitige Hooks oder Branch-Schutzregeln der Hosting-Plattform verwendet werden, da clientseitige Hooks immer auf dem Rechner des Entwicklers liegen.
Verwandte Themen
- git commit — der Befehl, um den sich pre-commit- und commit-msg-Hooks drehen.
- Commits signieren — Autorschaft prüfen, oft in Verbindung mit Hooks eingesetzt.
- Git config — wo
core.hooksPathund andere Einstellungen gespeichert werden. - Git alias — Abkürzungen für die Befehle, die Hooks ausführen.