Git: post-receive-Hook erstellen, der nach dem Push in den Webordner ausliefert
Ein post-receive-Hook sorgt dafür, dass der Git-Server nach jedem Push die Dateien automatisch in den Webordner auscheckt. Dafür reicht ein kleines Skript im hooks-Verzeichnis des Repositorys, das Zielpfad, Git-Verzeichnis und Branch festlegt – und das ausführbar sein muss.
$ git log --graph Der Weg zur Lösung
-
Problem
Nach jedem Push von Hand auschecken
Das bare repository auf dem Server nimmt Pushes an, aber der Webordner bleibt, wie er ist. Jemand muss nachziehen – und vergisst es.
-
Erkenntnis
Git ruft nach dem Push selbst ein Skript auf
Der Hook post-receive läuft nach jedem angenommenen Push. Mit --work-tree und --git-dir kann er aus dem bare repository in einen fremden Ordner auschecken.
-
Lösung
Hook anlegen und ausführbar machen
Sechs Zeilen Skript im hooks-Ordner, chmod +x – seitdem landet jeder Push auf dem Branch direkt im Webordner.
Ein Git-Server nimmt Pushes entgegen, aber die Dateien landen nicht von allein im Webordner. Wer nach jedem Push von Hand in den Zielordner wechselt und auscheckt oder gar per FTP kopiert, vergisst das irgendwann – und liefert einen alten Stand aus. Die Lösung ist ein post-receive-Hook: ein kleines Skript im Repository, das Git nach jedem angenommenen Push aufruft und das den gewünschten Branch direkt in den Webordner auscheckt.
Das Problem
Das Repository auf dem Server ist ein bare repository (ein Ordner wie project.git ohne eigene Arbeitskopie). Ein Push aktualisiert dort nur die Verwaltungsdaten; im Webordner, den der Webserver ausliefert, ändert sich nichts. Es fehlt der Schritt, der nach dem Push die Dateien des Branches an die richtige Stelle bringt – automatisch, ohne dass jemand daran denken muss.
Den Hook anlegen
Wir erstellen im hooks-Ordner des entsprechenden Repositorys eine Datei mit dem Namen post-receive:
sudo vi /pfad/zum/git/project.git/hooks/post-receive
Diese füllen wir mit folgendem Inhalt:
#!/bin/bash
TARGET="/pfad/zum/webordner/project"
GIT_DIR="/pfad/zum/git/project.git"
BRANCH="master"
echo "Push zum Webordner"
git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
TARGET ist der Webordner, GIT_DIR das Repository, BRANCH der Branch, dessen Stand ausgeliefert werden soll.
Ausführbar machen
Danach müssen wir die Datei noch ausführbar machen – sonst ignoriert Git den Hook stillschweigend:
sudo chmod +x /pfad/zum/git/project.git/hooks/post-receive
Warum das funktioniert
Git führt Skripte aus dem Ordner hooks zu festen Zeitpunkten aus. post-receive läuft auf dem Server, nachdem ein Push vollständig angenommen wurde – einmal je Push, egal wie viele Branches darin stecken. Was das Skript auf die Standardausgabe schreibt, sieht der Pushende in seinem Terminal, jeweils mit remote: davor; das echo im Skript ist also eine kleine Erfolgsmeldung.
Die beiden Optionen --work-tree und --git-dir trennen Arbeitskopie und Repository. Normalerweise liegen beide zusammen in einem Ordner; hier liegt das Repository als bare repository an einer Stelle und der Webordner an einer anderen. So kann Git den Branch in einen beliebigen Ordner auschecken, ohne dass dort ein .git-Verzeichnis entsteht. checkout -f erzwingt den Stand des Branches und überschreibt Änderungen, die jemand direkt im Webordner gemacht hat – gewollt, denn der Webordner ist kein Arbeitsplatz, sondern das Ziel.
Stolperfallen
- Nicht ausführbar: Ohne
chmod +xpassiert nichts, und Git meldet auch keinen Fehler. Wenn der Push durchgeht, aber im Webordner nichts ankommt, zuerst hier nachsehen. - Falscher Branch-Name: Heißt der Hauptbranch
mainstattmaster, schlägt der Checkout mit einer Meldung wiepathspec 'master' did not matchfehl – sichtbar in der Push-Ausgabe hinterremote:. - Zielordner und Rechte: Der Webordner muss existieren, und der Benutzer, der den Push entgegennimmt (meist der SSH-Benutzer des Git-Servers), braucht dort Schreibrechte. Gehört der Ordner dem Webserver-Benutzer, hilft eine gemeinsame Gruppe.
- Jeder Push löst aus: Das Skript prüft nicht, welcher Branch gepusht wurde. Auch ein Push auf einen Feature-Branch checkt den in
BRANCHeingetragenen Stand erneut aus – harmlos, aber gut zu wissen. - Handänderungen gehen verloren: Wegen
-fverwirft der Checkout alles, was jemand direkt im Webordner geändert hat. Konfigurationsdateien und Uploads, die nicht ins Repository gehören, deshalb außerhalb des Webordners ablegen oder per.gitignoreausnehmen – ignorierte Dateien lässt der Checkout in Ruhe.