Git muss nicht komplex sein, aber es gibt bestimmte Aspekte, die kompliziert sind und ein tieferes Verständnis erfordern – Git Hooks zum Beispiel. Das sind Skripte, die Git bei bestimmten Ereignissen automatisch ausführt.

Sie können zwar einfach sein, aber du hast viel mehr Möglichkeiten, sie effektiv zu nutzen. Dafür musst du jedoch alle Rädchen im Getriebe verstehen.

In diesem Beitrag befassen wir uns mit fortgeschrittenen Techniken für Git-Hooks, die einige Grundlagen beinhalten, wie man sie erstellt und installiert und vieles mehr.

Außerdem erklären wir Hook-Parameter und Umgebungsvariablen, geben Tipps und Tricks, gehen auf Fehlerbehebungsmethoden ein und behandeln viele weitere Themen.

Die Grundlagen von Git Hooks: Eine Fibel

Eine der wichtigsten Funktionen von Git sind seine Hooks: ein leistungsfähiger Mechanismus, mit dem du Aufgaben automatisieren, Standards durchsetzen und konsistente Arbeitsabläufe über den gesamten Lebenszyklus eines Projekts hinweg sicherstellen kannst.

Git-Hooks sind Skripte, die automatisch an bestimmten Punkten im Git-Workflow ausgeführt werden. Du kannst sie verwenden, um das Verhalten von Git an die Bedürfnisse deines Projekts anzupassen und zu erweitern. Hooks sorgen dafür, dass die Qualität des Codes erhalten bleibt, Tests durchgeführt und Verteilungen reibungslos organisiert werden.

Git bietet verschiedene Arten von Hooks, die jeweils in unterschiedlichen Phasen des Git-Workflows ausgelöst werden können:

  • Pre-commit. Diese Hooks werden ausgeführt, bevor du einen Commit abschließt. So kannst du Code-Stile durchsetzen, Tests ausführen oder auf Syntaxfehler prüfen.
  • Post-commit. Sie werden ausgeführt, nachdem du einen Commit erstellt hast. Er ist nützlich für Benachrichtigungen oder Logging.
  • Pre-push. Dieser Hook wird ausgelöst, bevor du den Code veröffentlichst, und ermöglicht es dir, Integrationstests durchzuführen, die Kompatibilität zu prüfen oder die Qualität sicherzustellen.
  • Post-Push. Der letzte Hook läuft, nachdem du einen Push durchgeführt hast. Er ist nützlich, um den Code in die Produktion zu überführen oder die Dokumentation zu aktualisieren.

Du findest die Hooks im Verzeichnis .git/hooks deines Git-Repositorys. Dort gibt es auch Beispiel-Hooks, die du als Vorlagen für deine eigenen Skripte verwenden kannst. Die Hooks decken eine Reihe von Aktionen ab und sind mit dem Präfix sample- gekennzeichnet:

Ein macOS Finder-Bildschirm, der ein lokales Verzeichnis mit 13 weißen Sample-Hooks-Dateien auf grauem Hintergrund zeigt.
Ein lokales Git-Verzeichnis mit Beispiel-Hooks-Dateien

Hooks werden bei verschiedenen Git-Aktionen ausgelöst. Ein Pre-Commit-Hook wird zum Beispiel ausgeführt, wenn du Änderungen überträgst, und ein Pre-Push-Hook wird ausgelöst, bevor du einen Push an eine andere Stelle sendest. Sobald du mehr über diese Auslöser weißt, kannst du Hooks strategisch einsetzen, um die Qualitätskontrolle zu verbessern und deinen Arbeitsablauf zu optimieren.

So erstellst und installierst du benutzerdefinierte Git-Hooks

Das Erstellen und Installieren von benutzerdefinierten Git-Hooks kann ein komplexer Prozess sein. Aber die Grundlagen, die du hier lernst, werden dich später bei der Entwicklung fortgeschrittener Hooks unterstützen. Gehen wir ein paar Konzepte durch, die für jeden Hook gelten, den du erstellst und installierst.

Auswahl eines geeigneten Hook-Typs

Die Wahl des richtigen Hook-Typs für deinen speziellen Anwendungsfall ist ein wichtiger erster Schritt. Du kannst damit beginnen, indem du deinen eigenen Arbeitsablauf und deine Bedürfnisse kennst. Hier ist eine kurze Checkliste mit Überlegungen zu diesem Thema:

  • Betrachte zunächst die verschiedenen Phasen deines Prozesses, wie z. B. die Codierung, die Tests und die Bereitstellung. Finde außerdem heraus, wo dieser Prozess von einer Automatisierung und Kontrolle profitieren könnte.
  • Finde dann die Stellen in deinem Arbeitsablauf, an denen häufig Fehler oder Unstimmigkeiten auftreten. Benutzerdefinierte Git-Hooks können hier helfen. Wenn du zum Beispiel vergisst, die Tests vor einem Commit auszuführen, kann ein Pre-Commit-Hook das Problem beheben.
  • Als Nächstes überlegst du dir, wann du den Hook innerhalb deines Workflows ausführen möchtest. Wenn du zum Beispiel sicherstellen willst, dass alle Commits den Coding-Standards entsprechen, ist ein Pre-Commit-Hook angebracht. Wenn du den Code validieren willst, bevor du ihn an die Gegenstelle sendest, ist ein Pre-Push-Hook besser geeignet.
  • Schließlich musst du sicherstellen, dass der von dir gewählte Hook-Typ mit deiner Entwicklungsumgebung und den von dir verwendeten Tools kompatibel ist. Überlege dir, welche Skriptsprache du für den Hook verwendest und in welcher Umgebung er ausgeführt werden soll.

An diesem Punkt solltest du in der Lage sein, klare Ziele für deinen Hook zu definieren. Es kann sogar sein, dass jedes Ziel eine andere Art von Hook erfordert. Es ist zwar verlockend, Skripte für alle möglichen Szenarien zu erstellen, aber es ist eine gute Idee, sich zuerst auf die kritischen Punkte zu konzentrieren.

Benennung und Platzierung von benutzerdefinierten Git-Hooks

Die richtige Benennung und Platzierung von benutzerdefinierten Git Hooks ist entscheidend für ihre Funktionalität und Wartbarkeit. Wie die Funktionen, Dateien, Klassennamen und vieles mehr in deinem Code sollten auch deine Git Hooks eine einheitliche und aussagekräftige Namenskonvention haben.

Wenn die Hooks im Laufe der Zeit mehrere Projekte unterstützen, solltest du Präfixe verwenden – vielleicht mit den Initialen des Entwicklers, einer Abteilung oder einem Firmennamen. In der Regel verwenden Git-Hooks Kleinbuchstaben und Bindestriche, um die Lesbarkeit zu verbessern – z. B. my-project-pre-commit.

Während du Git-Hooks im Verzeichnis .git/hooks deines Projektarchivs speichern kannst, sollten benutzerdefinierte Hooks in einem separaten Verzeichnis im Stammverzeichnis des Projekts abgelegt werden. So verhinderst du, dass sie bei einem Git-Update versehentlich überschrieben werden. Du solltest jedoch eine Versionskontrolle für diese Hooks zusammen mit dem restlichen Code deines Projekts einrichten.

So erstellst du einen einfachen benutzerdefinierten Git-Hook

Um einen einfachen Git-Hook zu erstellen, legst du in der Regel eine neue Datei mit dem Namen des gewünschten Hooks (z. B. pre-commit) in deinem Hooks-Verzeichnis an. Wir werden die Hook-Namen später auflisten, wenn wir über Parameter sprechen.

Bevor du eine Datei öffnest, um mit ihr zu arbeiten, solltest du sicherstellen, dass sie mit dem folgenden Befehlszeilen-Snippet ausführbar ist:

chmod +x path/to/file/hook-name

Denk daran, unsere Platzhalter durch die richtigen Informationen zu ersetzen. Wir werden im Laufe des Beitrags immer wieder auf dieses Snippet verweisen, da es eine typische Aktion sein sollte, wenn du einen neuen Git-Hook erstellst.

Sobald die Datei ausführbar und geöffnet ist, fügst du deine eigene Logik in deiner bevorzugten Skriptsprache hinzu. Das kann Bash, Python, Ruby oder eine andere sein. Die Erstellung solcher Skripte würde den Rahmen dieses Artikels sprengen. Später gibt es jedoch einige Pseudocode-Beispiele, um bestimmte Anwendungsfälle und Szenarien zu veranschaulichen.

Bevor du Änderungen überträgst, solltest du deinen Hook testen, indem du versuchst, die entsprechende Aktion (z. B. eine Übertragung) auszuführen. Dies ist der grundlegende Ansatz für die Erstellung von Git-Hooks, aber es gibt auch viele fortgeschrittene Anwendungsfälle. Darauf gehen wir als Nächstes ein.

Erstellen und Installieren von fortgeschrittenen Custom Hooks

Das Erstellen einfacher Git-Hooks wirst du im Laufe deiner Entwicklungskarriere häufig tun. Es gibt jedoch viele Situationen, in denen du fortgeschrittenere und komplexere Hooks brauchst. Im Folgenden sehen wir uns einige Anwendungsfälle und Beispiel-Hooks für verschiedene gängige Szenarien an.

Einen Hook erstellen, der den Code-Stil mit Linters erzwingt

Die Verwendung eines Linters zur Durchsetzung von Code-Styling ist eine fantastische Anwendung für Git-Hooks. Er kann dazu beitragen, eine einheitliche Codequalität in deinem Repository aufrechtzuerhalten, und ist etwas, von dem du viel profitieren kannst.

Natürlich solltest du einen Linter wählen, der zu der Programmiersprache deines Projekts passt. Black ist zum Beispiel fantastisch für Python. Wir werden hier ESLint für JavaScript verwenden, um einen Pre-Commit-Hook zu erstellen.

Installiere zunächst den Linter als globales oder lokales Paket in deinem Projekt. Dafür brauchst du Node.js und npm:

npm install eslint --save-dev

Als Nächstes navigierst du zu deinem Hooks-Verzeichnis in deinem Repo. Erstelle deine Pre-Commit-Datei und schreibe dann ein Skript, das den Linter auf deine bereitgestellten Dateien anwendet. Der Hook sollte den Commit verhindern, wenn der Linter irgendwelche Probleme findet. Hier ist ein grobes Beispiel:

#!/bin/sh

# Stash unstaged changes (optional but recommended)
git stash -q --keep-index

# Run the linter on staged files
npm run lint # Replace with the appropriate linting command
LINT_RESULT=$?

# Unstash the stashed changes (optional but recommended)
git stash pop -q

# Exit with the linter's exit code
exit $LINT_RESULT

Sobald du sichergestellt hast, dass der Hook ausführbar ist, teste ihn mit einem Commit. Der Pre-Commit-Hook sollte den Linter ausführen. Wenn es Verstöße gegen den Code-Stil gibt, kannst du den Commit nicht abschließen, bis du die Probleme behoben hast.

Natürlich solltest du einen Hook schreiben, der mit deiner eigenen Programmiersprache und deinem Linter funktioniert, je nach Projekt. Du könntest dieses Beispiel z. B. mit Linter-Konfigurationseinstellungen erweitern, es in deinen Build-Prozess integrieren und vieles mehr.

Implementiere einen Hook für die Ausführung von Tests vor einem Commit

Die Implementierung eines Pre-Commit-Hooks zur Ausführung von Tests vor einem Commit ist eine hervorragende Möglichkeit, um potenzielle Probleme frühzeitig zu erkennen. So kannst du sicherstellen, dass du nur zuverlässigen Code übergibst.

Für dieses Beispiel verwenden wir das Jest Testing Framework für JavaScript. Du solltest (wie immer) etwas Passendes für dein Projekt installieren:

npm install jest --save-dev

Wie bei jedem Hook navigierst du zu deinem Hooks-Verzeichnis, erstellst eine neue Datei, benennst sie und machst sie ausführbar. Von hier aus schreibst du ein Skript, das vor dem Commit Tests für alle bereitgestellten Dateien durchführt. Hier ist eine grobe Vorlage:

#!/bin/sh

# Stash unstaged changes (optional but recommended)
git stash -q --keep-index

# Run tests on staged files
npm test # Replace with the appropriate test command
TEST_RESULT=$?

# Unstash the stashed changes (optional but recommended)
git stash pop -q

# Exit with the test's exit code
exit $TEST_RESULT

Wenn du versuchst, Änderungen zu übertragen, führt der Hook deine Tests für die bereitgestellten Dateien aus. Bei fehlgeschlagenen Tests wird die Übertragung abgebrochen, und du solltest die Probleme beheben, bevor du die Übertragung erneut durchführst.

Entwickle einen Hook für die Automatisierung von Versionierung und Markierung

Eine hervorragende Möglichkeit, den Freigabeprozess zu rationalisieren, ist die Automatisierung der Versionskontrolle und des Taggings in Git. So stellst du eine konsistente Versionierung deiner gesamten Codebasis sicher.

Wähle zunächst ein für dein Projekt geeignetes Versionsschema. Das würde den Rahmen dieses Artikels sprengen, aber gängige Schemata sind Semantic Versioning (SemVer) oder ein benutzerdefiniertes Versionierungsmuster.

Als Nächstes musst du entscheiden, was dein Hook genau tun soll. Er könnte zum Beispiel die aktuelle Version lesen, sie nach einem bestimmten Schema erhöhen und die notwendigen Dateien mit der neuen Version aktualisieren. Außerdem solltest du ein Skript schreiben, das auf Basis der Version Tags erstellt und Git-Befehle verwendet, um leichtgewichtige oder mit Anmerkungen versehene Tags zu erstellen.

Sobald du die Berechtigungen für deine Datei erstellt und festgelegt hast, kannst du damit beginnen, deinen Hook zu schreiben. Das kann ein komplexer und sehr spezifischer Hook sein, der sich sogar von Projekt zu Projekt ändern kann. Die meisten Hooks dieser Art enthalten jedoch Folgendes:

  • Eine Funktion, die einen bestimmten Teil eines Versionsstrings (z. B. 1.2.3) erhöht und die neue Version zurückgibt.
  • Die Möglichkeit, die aktuelle Version aus einer speziellen Versionsdatei zu lesen.
  • Eine Funktion, die die neue Versionsnummer berechnet und angibt, welcher Teil inkrementiert werden soll. Zum Beispiel: 0 für Major, 1 für Minor, 2 für Patch.

Von hier aus sollte das Skript die Versionsdatei mit der neuen Nummer aktualisieren, ein leichtgewichtiges Tag mit der neuen Version erstellen und optional das neue Tag in ein entferntes Repository pushen. Sobald du die Änderungen überträgst, sorgt der Hook dafür, dass jede Übertragung mit der richtigen Version und dem richtigen Tag verknüpft wird.

Du wirst diesen Hook wahrscheinlich noch weiter an die Anforderungen deines Projekts anpassen wollen. So könntest du z. B. die Erstellung der ersten Tags, den Umgang mit Versionskonflikten und die Aktualisierung von Versionsverweisen in Dateien übernehmen.

Hook-Parameter und Umgebungsvariablen verstehen

Ein Grund, warum Git Hooks so leistungsfähig sind, ist die Art und Weise, wie sie mit dynamischen Variablen umgehen. Das kann jedoch ein komplexes Konzept sein, das es zu verstehen gilt. Im Folgenden werden wir uns sowohl die Umgebungsvariablen als auch die Hook-Parameter ansehen – und mit letzteren beginnen.

Wie Parameter an Hooks übergeben werden

Hooks können bestimmte Parameter von Git erhalten, um auf kontextbezogene Informationen aus deiner Hauptcodebasis zuzugreifen. Git setzt die Parameter zur Laufzeit automatisch, und obwohl du sie in den meisten Fällen nicht definieren musst, kann es sein, dass du sie angeben musst. Es ist wichtig, diese zu verstehen, um effektive Hooks zu entwickeln.

Hier ist ein Überblick über die wichtigsten Parameter für Hooks:

  • Git-Hooks verwenden Positionsvariablen, wobei sich $1 auf den ersten Parameter bezieht, $2 auf den zweiten Parameter und so weiter. Diese Parameter sind nicht willkürlich; sie haben bestimmte Bedeutungen und Zwecke. Sie sind zwar nicht „offiziell“, stellen aber akzeptierte Konventionen für den Zugriff auf die Werte von Parametern dar.
  • Die Reihenfolge der Parameter folgt einem bestimmten Muster. Git übergibt diese Parameter in einer bestimmten Reihenfolge an dein Hook-Skript, die sich aus dem Kontext des Hook-Ereignisses ergibt.
  • Die Variablennamen spiegeln den allgemeinen Zweck der Parameter wider. Zum Beispiel enthält $1 oft den Pfad zu einer Datei, während $2 die Quelle einer Aktion sein kann.

Wenn du einen Parameter hinzufügst, den der Hook nicht aufrufen kann, kann das Skript ihn in der Regel nicht verwenden. Parameter sind spezifisch für einen bestimmten Hook und Ausführungskontext. Um Probleme zu vermeiden, solltest du nur dokumentierte Parameter verwenden. Du kannst jedoch den Wert eines Positionsparameters einer anderen Variablen zuweisen und ihn dann in deinem Skript verwenden:

#!/bin/sh

# Assign $1 to the variable EXAMPLE
EXAMPLE=$1

# Use EXAMPLE variable
echo "The commit message file is: $EXAMPLE"

In diesem Fall hat die Variable EXAMPLE denselben Wert wie $1, nämlich den Pfad zur Datei der Übergabemeldung. Wenn du jedoch die dokumentierten Variablennamen verwendest, wird dein Code verständlicher.

Beachte, dass du in manchen Fällen die Standardeingabe (stdin) verwendest, um Parameter zu definieren. In diesem Fall solltest du diese Elemente in deine Hooks einbauen.

Git Hook Parameterwerte und Definitionen finden

Da jeder Git-Hook seine eigenen Parameter hat, brauchst du wahrscheinlich eine Referenz, um herauszufinden, welche Parameter für deine spezielle Anwendung gelten. Die gute Nachricht ist, dass es mehrere Möglichkeiten gibt, dies zu tun.

In der offiziellen Git-Hook-Dokumentation findest du zum Beispiel einige der gängigsten Parameter. Am besten ist es jedoch, wenn du einen der Git-Hooks als Beispiel öffnest. Diese bestehen aus einem Mini-Leitfaden, der dir zeigt, wie du den Hook skriptest und der auch die Parameterdefinitionen für dich enthält:

Ein Beispiel für eine Git-Hook-Datei in NeoVim auf macOS. Es zeigt einen kommentierten Abschnitt, der erklärt, wie man den Hook kodiert, zusammen mit den entsprechenden Parametern, die darin verwendet werden können. Es gibt auch einen Teil des Bash-Codes für den Hook.
Eine Beispiel-Git-Hook-Datei in NeoVim

Sie eignen sich hervorragend, um sich mit Git-Hooks vertraut zu machen, und helfen dir vielleicht sogar dabei, sie zu kodieren.

Umgebungsvariablen

Git-Hooks können Argumente aus der Befehlszeile und von stdin, abrufen, wie wir bereits besprochen haben. Sie können aber auch Argumente aus der Umgebung selbst abrufen, wenn diese in einer bash Shell läuft.

Mit diesen Umgebungsvariablen kannst du das Verhalten deiner Git-Hooks anpassen und Entscheidungen auf der Grundlage verschiedener Aspekte des Git-Workflows treffen. Auf diese Weise kannst du dynamische und kontextabhängige Git-Hooks erstellen. Du kannst sie zum Beispiel verwenden, um Commit-Nachrichten zu überprüfen, den Zugriff auf bestimmte Zweige zu kontrollieren oder benutzerdefinierte Aktionen auf der Grundlage der Identität des Autors auszulösen.

Alle Umgebungsvariablen aufzulisten, würde den Rahmen dieses Beitrags sprengen. Wir empfehlen dir, die Git-Dokumentation und die Beispiel-Hooks zu lesen, um herauszufinden, welche Variablen verwendet werden.

Testen der Werte von Umgebungsvariablen

Git setzt normalerweise automatisch verschiedene Umgebungsvariablen, je nachdem, welchen Hook es aufruft. Das kann zu Problemen führen, wenn du nicht weißt, was gesetzt wird. Nimm zum Beispiel das folgende Ergebnis für die Variable GIT_REFLOG_ACTION für die Hooks „pre-rebase“ und „post-merge“:

  • pre-rebase. GIT_REFLOG_ACTION=rebase
  • post-merge. GIT_REFLOG_ACTION=’pull other master’

Zum Glück gibt es eine Möglichkeit zu testen, wie Git mit Umgebungsvariablen umgeht, indem du ein kleines Snippet in deinem Hook verwendest:

#!/bin/bash

echo Running $BASH_SOURCE
set | egrep GIT
echo PWD is $PWD

Um den Code zusammenzufassen: Zeile zwei gibt das Skript aus, das gerade läuft; Zeile drei zeigt alle Umgebungsvariablen an und filtert sie dann nach denen, die „GIT“ im Namen haben; Zeile vier gibt das aktuelle Arbeitsverzeichnis aus.

Sobald du das Skript ausführst, siehst du eine Ausgabe, die den Umgebungsvariablen entspricht, die mit deinem Hook verbunden sind. So kannst du sicherstellen, dass deine eigenen Git-Hooks die Umgebungsvariablen so nutzen können, wie du es möchtest.

Tipps und Tricks zum Verwalten und Teilen deiner Git Hooks

Die Verwaltung von Git Hooks in einem Team oder einer Organisation ist wichtig, um einheitliche Entwicklungspraktiken zu gewährleisten und deine Arbeitsabläufe effizient zu automatisieren. Ein Beispiel dafür ist die Zuweisung eines eigenen Hooks-Verzeichnisses. Hier gibt es zwei Ratschläge, die wir dir geben können:

  • Lege ein zentrales Repository oder einen gemeinsamen Speicherort an, in dem du standardisierte Hooks speicherst. Du kannst diese Hooks in mehreren Projekten wiederverwenden und das Repository klonen oder verlinken, um einen globalen Zugriff zu ermöglichen.
  • Organisiere deine Hooks in einer Registry oder Verzeichnisstruktur. So kann dein Team die Hooks, die es braucht, leicht finden und verwenden.

Je wahrscheinlicher es ist, dass Hooks in mehreren Projekten eingesetzt werden, desto wichtiger ist die Dokumentation. Du solltest eine umfassende Dokumentation führen, die den Zweck, die Verwendung und die Konfigurationsoptionen für jeden Hook im Repo beschreibt. Code-Reviews und Aktualisierungsstrategien für diese globalen Hooks sind ebenfalls wichtig.

Wir empfehlen dir außerdem, benutzerdefinierte Hooks zusammen mit der Codebasis deines Projekts im Versionskontrollsystem (VCS) zu speichern. So wird sichergestellt, dass das gesamte Team Zugriff auf die gesamte Bibliothek der Hooks hat.

Server-seitige Git-Hooks verwenden

Serverseitige Hooks werden auf dem Server ausgeführt, der das zentrale Git Repo hostet. So kannst du Richtlinien durchsetzen, Prüfungen durchführen oder Aktionen auf der Serverseite auslösen.

Du hast zwei Möglichkeiten, deine serverseitigen Hooks zu speichern: innerhalb des VCS neben deinem Projekt oder in separaten Repositories.

Speicherung von serverseitigen Hooks in einem VCS

Es hat zwei Vorteile, wenn du dein VCS zum Speichern von serverseitigen Hooks verwendest. Erstens kannst du sicherstellen, dass die Hooks die gleiche Versionierung und Wartung haben wie der Rest deiner Codebasis. Zweitens musst du nur ein Repository klonen, um sowohl auf den Projektcode als auch auf die Hooks zuzugreifen.

Je nach Art der Hooks kann es jedoch zu Sicherheitsbedenken führen, wenn die Hooks auf sensible Daten zugreifen, wenn sie im selben Repository gespeichert werden. Und wenn die Hooks komplex sind oder bestimmte Konfigurationen erfordern, kann dies die Komplexität deines Haupt-Repos erhöhen.

Server-seitige Hooks in separaten Repositories speichern

Wenn du serverseitige Hooks in separaten Repos aufbewahrst, kannst du sie unabhängig von deiner Codebasis aktualisieren und versionieren, was mögliche Konflikte reduziert. Diese Modularität kann zu mehr Flexibilität führen.

Außerdem kannst du diese Hooks in Repositories mit eingeschränktem Zugriff speichern. So kannst du das Risiko der Offenlegung sensibler Daten verringern.

Im Gegensatz dazu kann die Pflege mehrerer Repositories zusätzlichen Aufwand bedeuten. Wenn Hooks auf bestimmte Versionen deiner Hauptcodebasis angewiesen sind, kann es außerdem eine Herausforderung sein, Änderungen zwischen deinen Repos zu koordinieren.

Automatisierte Hooks-Installationen

Wenn du die Installation von Hooks in mehreren Repositories automatisierst, sparst du Zeit und sorgst für Konsistenz in deinem Entwicklungsworkflow. Mithilfe von Skripten und Vorlagen kannst du ganz einfach Hooks in verschiedenen Repositories einrichten, ohne manuell eingreifen zu müssen.

Der Prozess beginnt mit einem speziellen Repository, das deine globalen Hooks enthält. Du solltest diese standardisieren: Vermeide es zum Beispiel, Pfade oder Werte speziell für ein einzelnes Repository zu kodieren.

Von hier aus kannst du beginnen, dein Installationsskript zu schreiben. Der folgende Pseudocode klont zum Beispiel das Template-Repository eines Hooks und kopiert (oder „symlink“) die Hooks in das Verzeichnis .git/hooks des jeweiligen Repositorys:

# Example installation script
# Usage: ./install_hooks.sh /path/to/repository
TEMPLATE_REPO="https://github.com/yourusername/hooks-template.git"
REPO_PATH="$1"
REPO_NAME=$(basename "$REPO_PATH")

# Clone the template repository
git clone --depth 1 "$TEMPLATE_REPO" "$REPO_NAME-hooks"

# Copy or symlink hooks to the repository
cp -r "$REPO_NAME-hooks/hooks" "$REPO_PATH/.git/"
rm -rf "$REPO_NAME-hooks"
echo "Hooks installed in $REPO_NAME”

Sobald du deine Änderungen gespeichert hast, kannst du das Installationsskript für jedes Repository ausführen, in dem du die Hooks installieren möchtest:

./install_hooks.sh /path/to/repository1
./install_hooks.sh /path/to/repository2
# …

Nimm Änderungen im Vorlagen-Repository vor, wenn du Hooks aktualisieren oder hinzufügen musst. Wenn du das nächste Mal das Installationsskript in einem Repository ausführst, werden die aktualisierten Hooks installiert.

Git-Vorlagen

Mit Git-Vorlagen kannst du allgemeine Hooks und Konfigurationen für neue Repositories definieren. Sie bieten einen systematischen Ansatz, der dir dabei hilft, Einstellungen, Konfigurationen und andere Elemente zu automatisieren, wenn du neue Repositories erstellst oder klonst. Auf diese Weise kannst du sicherstellen, dass jedes Projektarchiv deinen typischen und bewährten Verfahren entspricht.

Sobald du ein Vorlagenverzeichnis erstellt und deine Hook-Skripte hinzugefügt hast, kannst du Git so konfigurieren, dass es das Verzeichnis als Vorlage für neue Repositories verwendet. Du kannst dies global oder lokal für jeden Benutzer einrichten.

Für globale Konfigurationen zeigst du auf dein Hooks-Vorlagenverzeichnis:

git config --global init.templateDir /path/to/hooks-template

Für lokale Konfigurationen kannst du das genaue Repo angeben:

git init --template=/path/to/hooks-template

Wenn du mit git init ein neues Repository erstellst oder ein bestehendes Repository klonst, kopiert Git automatisch den Inhalt deines hooks-Vorlagenverzeichnisses in das .git-Verzeichnis des neuen Repos.

Und schließlich kannst du neben den allgemeinen Vorlagen-Hooks auch individuelle Hooks für bestimmte Anforderungen einrichten. Ein Skript könnte zum Beispiel nach einer repositoryspezifischen Hook-Konfigurationsdatei suchen und diese verwenden, wenn sie vorhanden ist.

Typische Praktiken, die dir helfen, sichere Git-Hooks zu pflegen

Die Verwendung von Git-Hooks kann für die Prozessautomatisierung und die Durchsetzung typischer Praktiken sehr hilfreich sein. Sie können aber auch Schwachstellen verursachen, wenn du deine Hooks nicht gut genug verwaltest.

Hier ist eine kurze Liste von Praktiken, die du für deine eigenen Hooks anwenden kannst:

  • Achte darauf, dass du die Berechtigungen für Hooks überprüfst und einschränkst, besonders wenn es sich um Beispiele von Drittanbietern handelt.
  • Überprüfe und bereinige immer deine Eingabeparameter, um Code-Injections zu verhindern. Verwende sichere Praktiken, z. B. vermeide die direkte Verwendung von Benutzereingaben in deinen Skripten.
  • Achte darauf, dass die Hooks keine vertraulichen Informationen enthalten. Hier sind Umgebungsvariablen oder ein sicherer Speicher von großem Nutzen.
  • Überprüfe und teste Hooks regelmäßig, um unbeabsichtigten Ressourcenverbrauch zu verhindern. Dies könnte sogar zu Distributed Denial of Service (DDoS)-Angriffen führen.

Außerdem solltest du einen gründlichen und umfassenden Test- und Überprüfungsprozess einführen. So kannst du Schwachstellen und andere Fehler in Zukunft vermeiden.

Validierung

Wir sollten mehr über die Implementierung einer angemessenen Validierung und Fehlerbehandlung für deine Hooks sprechen. Das ist wichtig, um Zuverlässigkeit, Stabilität und Sicherheit zu gewährleisten.

Du musst zum Beispiel immer alle Eingaben oder Parameter validieren, die deine Hook-Skripte erhalten. Es gibt aber noch viel mehr, was du tun kannst, um eine gute Validierung sicherzustellen. Du kannst sicherstellen, dass sich das Repository in dem erwarteten Zustand befindet, damit der Hook erfolgreich ausgeführt werden kann. Überprüfe zum Beispiel bei einem Pre-Commit-Hook, ob du die notwendigen Dateien vor dem Commit bereitstellst.

Ein Teil der iTerm Anwendung für macOS, der ein Beispiel für einen Git-Hook zeigt, der in einem NeoVim-Fenster geöffnet ist. Es gibt einen kleinen Codeabschnitt für einen Pre-Push-Hook, mit einem Exit 0 Code am Ende der Suite.
Ein Ausschnitt aus einer Git-Hook-Datei mit dem Exit 0-Code als Endzeile

Auch die Fehlerbehandlung ist wichtig. Exit-Codes sind in Hooks genauso wichtig wie in deiner Codebasis, ebenso wie Fehlerprotokolle und informative Fehlermeldungen. wie bei größeren Codebasen sollte auch hier ein „elegantes Versagen“ dein Ziel sein.

In der Praxis kann es natürlich sein, dass deine Hooks eine komplexere Validierungs- und Fehlerbehandlungslogik benötigen. Das bedeutet, dass regelmäßige Tests noch wichtiger sind als bisher.

Unbeabsichtigte zerstörerische Handlungen

Unfälle passieren. Deshalb ist es wichtig, dass du deine Git-Hooks so einrichtest, dass sie ungewollte zerstörerische Aktionen verhindern, um Datenverluste oder Schäden zu vermeiden. Hooks können im Wesentlichen als Sicherheitsnetze fungieren, indem sie den Benutzer auf potenziell schädliche Aktionen hinweisen.

Pre-Receive- und Pre-Commit-Hooks eignen sich gut dafür. Sehen wir uns kurz an, wie diese beiden Hooks helfen können:

  • Pre-receive hooks helfen bei serverseitigen Prüfungen. Sie werden ausgelöst, bevor neue Zweige oder Tags vom Client akzeptiert werden. Dein Skript sollte eingehende Verweise untersuchen, auf Aktionen wie Force Pushes oder Zweiglöschungen prüfen und den Nutzer zur Bestätigung auffordern. Du solltest auch die gepushten Referenzen analysieren, um festzustellen, ob sie Aktionen wie Force Pushing (--force) oder Branch Deletion beinhalten.
  • Pre-Commit-Hooks arbeiten auf der Client-Seite und werden ausgeführt, bevor du einen Commit finalisierst. Sie verhindern zwar nicht direkt zerstörerische Aktionen auf dem Server, aber sie können helfen, lokale Fehler vor dem Push zu vermeiden. Dein Skript sollte die bereitgestellten Änderungen analysieren und nach Elementen wie force push in den Commit-Nachrichten suchen. Daraufhin wird eine Warn- oder Fehlermeldung für den Benutzer angezeigt.

Unabhängig davon, welche Methoden du einsetzt, müssen sie sicher, effizient und optimal für deine Bedürfnisse sein. Dies erfordert eine gründliche Überprüfung und Teststrategie.

Überprüfen und Testen von Git-Hooks

Das Überprüfen und Testen von Hooks ist unerlässlich, um sicherzustellen, dass sie richtig funktionieren und mit deinem Entwicklungsablauf übereinstimmen. Peer Reviews, eine klare Dokumentation, eine Fülle von Kommentaren und vieles mehr können dazu beitragen, dass die Hooks produktionsreif sind.

Beim Testen ist es wichtig, verschiedene Beispieldaten isoliert zu verwenden. Du kannst auch automatisierte Regressions- oder Integrationstests durchführen.

Schließlich raten wir dir, die Hooks in verschiedenen Umgebungen zu testen (z. B. auf deinen Entwicklungs-, Staging- und Produktionsservern), um sicherzustellen, dass sie ein einheitliches Verhalten zeigen. Eine Echtzeit-Protokollierung hilft dir dabei, denn sie zeigt dir, was passiert, wenn die Daten von Server zu Server wandern.

Fehlersuche bei deinen Hooks

Wie bei jeder Codebasis kann es sein, dass du auch bei deinen Hooks eine Fehlersuche durchführen musst – sogar über mehrere Versuche hinweg. Unabhängig von der Art deines Git-Hooks wirst du feststellen, dass immer wieder dieselben Fehler auftauchen. Bei vielen dieser Fehler handelt es sich um einfache Probleme, die alle Arten von Projekten betreffen, z. B. Syntaxfehler, Probleme mit Berechtigungen, die Verwendung relativer oder fest kodierter Pfade und vieles mehr.

Es ist aber auch eine gute Idee, nach fehlenden Abhängigkeiten zu suchen, denn einige Hooks sind auf externe Tools, Dateien oder Bibliotheken angewiesen. Daher musst du sie in der Umgebung, in der du den Hook ausführst, verfügbar machen.

Es gibt jedoch bestimmte Probleme, die bei Git-Hooks auftauchen können. Zum Beispiel sollten Hooks mit einem Statuscode ungleich Null beendet werden, um einen Fehler anzuzeigen. Außerdem sollten Hooks keine Endlosschleifen enthalten. Wenn du beides nicht beachtest, kannst du unerwartetes Verhalten verursachen und deinen Arbeitsablauf stören.

Es kann auch vorkommen, dass Konflikte zwischen zwei Hooks zu unbeabsichtigten Wechselwirkungen und Konsequenzen führen. Sogenannte „Race Conditions“ können deine Erwartungen ebenfalls beeinträchtigen. Das ist der Fall, wenn zwei oder mehr Hooks durch ähnliche Ereignisse ausgelöst werden, aber einer vor dem anderen abgeschlossen wird – das hat Auswirkungen auf das von dir erwartete Endergebnis.

An dieser Stelle sind Überprüfungen und Tests besonders wichtig. Auch die Dokumentation ist wichtig, um Probleme zu vermeiden und sicherzustellen, dass die Hooks so funktionieren, wie du es erwartest.

Apropos Dokumentation: Das Referenzmaterial von Git ist eine wichtige Lektüre. Zusammen mit diesem Artikel und vielleicht der unabhängigen Git Hooks-Anleitung (über GitHub Pages) solltest du nicht allzu viel Lesestoff benötigen.

Die Git Hooks Website eines Drittanbieters mit einer Einführung in Hooks und einer Erklärung. Sie verwendet schwarzen Text auf weißem Hintergrund. In der Ecke befindet sich das GitHub-Symbol, das darauf hinweist, dass die Seite auf GitHub Pages gehostet wird.
Die GitHooks Guide Website

Vielleicht möchtest du dir aber auch Apps ansehen, die dir bei der Verwaltung von Git Hooks helfen. Lefthook wird regelmäßig aktualisiert und bietet viel Unterstützung auf GitHub, während Husky sich hervorragend für das Linting deiner Commit-Nachrichten eignet.

Die Vorteile der Integration von Hooks in Continuous Integration (CI/CD) Pipelines

CI/CD-Pipelines funktionieren gut mit Git-Hooks, da diese Skripte dir helfen können, Aufgaben zu automatisieren, eine gleichbleibende Qualität zu gewährleisten und Sicherheitsüberprüfungen durchzuführen.

Mit Pre-Commit-Hooks kannst du zum Beispiel Code-Qualitätsprüfungen wie Linting, statische Analyse und Formatierung durchführen. Wenn es um das Testen geht, kannst du in der Pre-Commit-Phase Unit-Tests, Testsuiten oder andere automatisierte Prüfungen auslösen. Mit Pre-Push-Hooks hingegen kannst du Integrationstests, Sicherheitsscans und vieles mehr durchführen.

Der Einsatz von Hooks in deinen CI/CD-Pipelines bietet dir viele Vorteile:

  • Konsistenz. Mit Hooks kannst du konsistente Praktiken für alle Commits und Bereitstellungen durchsetzen, was die Fehlerquote in allen Bereichen reduziert.
  • Automatisierte Prüfungen. Du kannst Codequalitätsprüfungen, Tests, Sicherheitsüberprüfungen und andere wichtige Aufgaben automatisieren. Dadurch wird der manuelle Aufwand reduziert und du hast mehr Zeit für andere Aufgaben.
  • Frühzeitige Erkennung von Problemen. Mit Hooks kannst du Probleme frühzeitig im Entwicklungsprozess erkennen und so verhindern, dass sie sich in deiner Pipeline ausbreiten.
  • Geringere Bereitstellungsrisiken. Mit automatisierten Prüfungen und Tests, die durch Hooks ausgelöst werden, kann das Risiko, fehlerhaften Code einzusetzen, erheblich reduziert werden.

Da du mit der API von Kinsta CI/CD-Pipelines einrichten kannst, kannst du auch hier Git-Hooks integrieren. Mit Kinsta kannst du dein gesamtes Repo von einem remoten Standort abrufen und Pushes mit einem Plugin eines Drittanbieters wie WP Pusher durchführen.

Die WP Pusher-Startseite hat einen blauen Hintergrund und zeigt eine Tagline und eine Beschreibung des Plugins sowie einen Screenshot des Einstellungsbildschirms im WordPress-Dashboard.
Die WP Pusher-Startseite

Das bedeutet natürlich auch, dass du die Möglichkeit hast, Git-Hooks zu verwenden. So kann deine Kinsta-Installation diese leistungsstarken Skripte in deinem Repo nutzen.

Zusammenfassung

Git ist ein unverzichtbares Werkzeug für jedes Entwicklungsprojekt, aber vor allem ein Aspekt kann deinen Arbeitsablauf bei der Programmierung und Bereitstellung von Inhalten enorm beschleunigen. Mit Git Hooks kannst du Skripte in einer Reihe von Sprachen erstellen, um verschiedene Aspekte deines Versionskontrollprozesses zu automatisieren. Es ist ein einfaches Konzept mit einem etwas komplexen Unterbau.

Unser Beitrag zeigt dir, wie du Git Hooks mit fortgeschrittenen Techniken optimal nutzen kannst. Du kannst sie sowohl lokal als auch serverseitig verwenden, sie mit Parametern und Variablen dynamisch gestalten, mit mehreren Remote-Repos arbeiten und vieles mehr. Wir sind der Meinung, dass Git Hooks zu deiner Geheimwaffe werden könnten, um die Produktivität, die Codequalität und die Projektdurchlaufzeit zu steigern.

Hast du Fragen zu Git Hooks und wie du sie einsetzen kannst? Lass es uns in den Kommentaren unten wissen!

Jeremy Holcombe Kinsta

Content & Marketing Editor at Kinsta, WordPress Web Developer, and Content Writer. Outside of all things WordPress, I enjoy the beach, golf, and movies. I also have tall people problems ;).