Erzwinge, dass git nach dem Empfang einen Hook ausführt, auch wenn alles "aktuell" ist.

70

Wie erzwinge ich gitdas Ausführen eines post-receiveHooks auf einem Server, auch wenn ich kein neues Commit zum Pushen habe?

Hintergrund

Ich verwende git, um eine Website automatisch auf einem Server bereitzustellen. Ich habe ein nacktes Repo in einem geschützten Bereich des Servers und einen post-receiveHook, der den Inhalt auscheckt und bestimmte Dateien systematisch in einen public_htmlOrdner kopiert . (Inspiriert von diesem Tutorial )

Ich hatte es satt, den post-receiveHook manuell auf dem Server zu ändern, sodass mein post-receiveHook jetzt tatsächlich eine neue Version von sich selbst aus dem Repo kopiert:

#!/bin/sh

rm -rf ~/../protected/*
GIT_WORK_TREE=~/../protected git checkout -f

# Rewrite over this file with any updates from the post-receive file
cp ~/../protected/post-receive hooks/post-receive

# Delete public_html
# Copy stuff public_html

Das Problem ist natürlich, dass der neue post-receiveHook nie ausgeführt wird. Eine scheinbar einfache Lösung wäre lediglich, erneut zu pushen, aber jetzt ist bereits alles auf dem neuesten Stand. Dies ist ärgerlich, da ich jedes Mal, wenn ich den post-receiveHook aktualisiere, ein neues Commit vortäuschen muss . Gibt es eine Möglichkeit, den post-receiveHook aufzurufen , ohne ein Commit vorzutäuschen oder sich ssheinzumischen?

Was ich versucht habe

git push
git push -f
AndyL
quelle
2
Ich weiß, dass dies spät ist, aber ich habe eine andere interessante Lösung gefunden, weil ich denselben Bereitstellungsmechanismus implementiere. Nachdem das abgeschlossen checkout -fist, benutze ich rm -rf ~/repo.git/refs/heads/master. Dadurch wird der Hauptzweig gelöscht und jedes Mal ein Push ermöglicht.
Sam Holmes

Antworten:

56

Verwenden Sie '--allow-empty'

Nach dem ersten Push, der das Skript ersetzt, können Sie Folgendes tun:

git commit --allow-empty -m 'push to execute post-receive'

Das --allow-emptyFlag überschreibt das Standardverhalten von git, das verhindert, dass Sie ein Commit durchführen, wenn keine Änderungen vorgenommen werden.

Verwenden Sie einen Alias ​​und machen Sie Ihr Leben noch einfacher

Fügen Sie Folgendes hinzu: ~/.gitconfig

[alias]
    pushpr = "!f() { git push origin master;git commit --allow-empty -m 'push to execute post-receive';git push origin master; }; f"

Jetzt mach es einfach git pushpr

git pushpr

Dadurch werden alle Änderungen an master weitergeleitet, was in Ihrem Fall dazu führt, dass Ihr Post-Receive-Ersatzskript erneut gesendet wird. Anschließend wird erneut (unter Verwendung des --allow-emptyFlags) ein Push ausgeführt, wodurch Ihr aktualisiertes post-receiveSkript ausgeführt wird.

AndrewD
quelle
1
Wenn Sie kein zusätzliches Commit wünschen, können Sie es --allow-emptymit --amendund kombinieren -m The message from the last commit, aber Vorsicht: Dadurch wird der Verlauf des letzten Commits neu geschrieben. Verwenden Sie es nur, wenn Sie der einzige Entwickler sind. Sie müssen das nächste Mal einen Druck erzwingen.
Andrew
12
@ Andrew Sie können ausführen git commit --allow-empty --amend --no-edit, um die Festschreibungsnachricht wiederzuverwenden, ohne sie erneut einzugeben oder einen Editor zu öffnen.
Thomasd
@ Trdarr Oh, unglaublich. Ich mache total einen Alias ​​dafür.
Andrew
2
@ Thomasd guter Rat. Mit --amend --no-editbrauchst du nicht --allow-emptymehr.
Lachelic
Hinweis: Dadurch wird ein neues Commit im Verlauf erstellt. Es ist also im Grunde eine bequeme Möglichkeit, ein Commit vorzutäuschen. Etwas, das der Fragesteller nicht will.
Pixelbrackets
24

Ich weiß, dass dies wahrscheinlich als "gefährlich" eingestuft wird, aber ich lebe gerne am Rande.

Ich lösche einfach den Remote-Zweig und drücke ihn dann erneut. Stellen Sie zunächst sicher, dass Ihre lokale Niederlassung auf dem neuesten Stand ist, um die Wahrscheinlichkeit von Datenverlusten zu begrenzen.

Wenn ich also nach dem Empfang auslösen möchte, um in meinem Fall den Testzweig zur Bereitstellung zu bringen, tue ich nur Folgendes:

$ git push origin :testing
$ git push origin testing

Akzeptiere dies jedoch nicht als Antwort. Es ist eher eine Sache zu Ihrer Information.

Jamie Carl
quelle
4
Dies ist praktisch, wenn es sich wirklich nur um eine schreibgeschützte Fernbedienung handelt.
Alan
2
Großartig für nackte Git-Repos im Heroku-Stil
Ben Winding
1
Sie müssen ausgeführt git config receive.denyDeleteCurrent falsewerden, um den Remote-Zweig löschen zu können
Ben Winding
13

Ich fürchte, Sie müssen ssh zum Server und das Hook-Skript manuell ausführen. git pushLässt den Server nicht die Pre-Push- , Pre-Receive- und Post-Receive- Hooks ausführen , wenn nichts hinzugefügt wurde (dh wenn git alles auf dem neuesten Stand druckt ).

Der Rest der Antwort bezieht sich auf die Versionsverfolgung des Post-Receive- Hooks, sodass Sie ihn ändern können, ohne ihn an den Server zu senden.

Fügen Sie do-post-receivedem lokalen Repository ein Shell-Skript mit dem Namen hinzu :

$ ls -ld .git
$ echo 'echo "Hello, World!"' >do-post-receive
$ git add do-post-receive
$ git commit do-post-receive -m 'added do-post-receive'

Ersetzen Sie Ihren hooks/post-receiveHook am Server durch:

#! /bin/sh
while read OLDID NEWID BRANCH; do
  test "$BRANCH" = refs/heads/master && eval "$(git show master:do-post-receive)"
done

(Stellen Sie sicher, chmod 755 hooks/post-receiveauf dem Server.)

Übertragen Sie Ihre Änderungen vom lokalen Repository auf den Server und beobachten Sie, wie Ihr do-post-receiveCode ausgeführt wird:

$ git push origin master
...
remote: Hello, World!
...
pts
quelle
Sehr schlau! Leider kann ich dies für eine Weile nicht ausprobieren, um die Annahme zu geben ... Aber sei geduldig mit mir.
AndyL
Klingt vielversprechend, mehr als meine Antwort. +1
VonC
Das hat bei mir überhaupt nicht funktioniert. Ich denke, Sie sollten die Änderungen jedes Mal besser löschen und stattdessen einen vollständigen Repository-Push durchführen.
Jay Taylor
Ja, leider funktioniert es nicht und keiner der Pre-Push-, Pre-Receive- oder Post-Receive-Hooks wird auf dem Server ausgeführt, wenn keine Änderungen vorgenommen wurden.
Punkte
Du bist fast da! Das Problem ist , dass die Post erhält Skript mit einem --censored-- ausgeführt wird Rohr als Standard - Eingang, so dass die Eingabe gelesen zu haben mit while read ...es gibt wenig oder nichts mehr übrig für das do-post-receiveDrehbuch zu lesen. (Ich habe ein Ding namens geschrieben git_xhook, das mehrere, erweiterte Hooks erlaubt; es ist zu groß für diesen Kommentar, aber das könnte dich dorthin bringen.)
torek
11

Wenn Sie ein falsches neues Commit vermeiden möchten , können Sie es einfach verwenden

git commit --amend --no-edit

Dadurch wird der letzte Festschreibungsdatensatz geändert und Sie können ihn verwenden git push -f(vorausgesetzt, Ihre Antwort besagt, dass Sie mit dem Überschreiben einverstanden sind).

  • Praktisch: Es wird kein zusätzliches Commit erstellt
  • gut: Es wird kein expliziter Pfad für den Hook im Remote-Repo verwendet
  • schlecht: Sie überschreiben den Verlauf, was in Ihrem Anwendungsfall in Ordnung ist, aber nicht in einem gemeinsam genutzten Repository verwendet werden sollte

Ich benutze diesen Befehl relativ oft, um etwas im letzten Commit vor dem Push zu reparieren, also habe ich einen Alias ​​dafür erstellt:

git config --global alias.amend 'commit --amend --no-edit'

Jetzt kann ich es direkt für den Anwendungsfall als Ihr ( git amend) oder verwenden

  • So fügen Sie (alle) geänderten Dateien zum letzten Commit hinzu: git amend -a
  • So ändern Sie die Nachricht: git amend -m 'better message'
lachend
quelle
1
Danke, du hast mir gerade viel Ärger erspart :)
Zdenek F
Bitte. Ich bin froh, dass meine Antwort unter den anderen immer noch nützlich ist.
Lachelic
3

Ich habe versucht, leere Commits zu erstellen und den Upload-Zweig zu löschen .

Aber was ist mit einem direkten ssh-Befehl:

ssh your_host /path/to/your_repo/hooks/post-receive
Websites
quelle
2
Das mögliche Problem bei diesem Ansatz ist, dass sich die Umgebungsvariablen / -konfigurationen für Ihre interaktive Shell-Anmeldung möglicherweise vom Git-Push unterscheiden und Sie möglicherweise unerwartetes Verhalten erhalten.
Cgseller
Wenn Sie sicherstellen müssen, dass der Befehl in der Ferne mit Remote-Umgebungen ausgeführt wird ssh host bash -cl '/path/to/post-receive', bin ich mir jedoch nicht sicher
Sites
2

In meinem Fall logge ich mich bei remote ein und starte:

$ sh project.git/hooks/post-receive

funktioniert gut!

Cosme Marins
quelle
2

Ich habe eine Bash-Funktion gemacht, um dies zu tun. Es wird davon ausgegangen, dass Sie über einen SSH-Zugriff verfügen ~/.ssh/config, der entsprechend eingestellt werden kann. Die Standardfernbedienung ist origin

kick-git() {
    remote="${1:-origin}"
    ssh $(echo $(git remote get-url "$remote")/hooks/post-receive | tr ':' ' ')
}

Quelle und ausführen kick-git [remote]

Bryce Guinta
quelle
2

Nach dem Empfang ist der falsche Ort für künstliche Befehlsantworten.

Sie möchten Ihre serverseitigen Goodies im Pre-Receive-Exit, abhängig von der aktualisierten Referenz - tun git update-ref refs/commands/update-hooks @Sie dies zB auf dem Server, dann können Sie es zB git push server +@:commands/update-hooksund im Pre-Receive des Servers können Sie

while read old new ref; do case $ref in
commands/update-hooks)
        maybe check the incoming commit for authorization
        update hooks here
        echo the results from the update
        denypush=1
        ;;
refs/heads/master)
        extreme vetting on master-branch updates here
        ;;
esac; done

((denypush)) && exit $denypush
jthill
quelle
1

Ich mag den Vorschlag von Jamie Carl, aber er funktioniert nicht und ich habe den Fehler erhalten:

remote: error: Standardmäßig wird das Löschen des aktuellen Zweigs abgelehnt, da der nächste Fehler: 'git clone' nicht dazu führt, dass eine Datei ausgecheckt wird, was zu Verwirrung führt.

In meinem Fall teste ich Post-Receive-Hooks auf meinem lokalen Host gegen ein nacktes Repository. Warnung / super wichtig, führen Sie diesen Befehl nur auf dem remoteServerstandort aus!

git update-ref -d refs/heads/develop 

Dadurch wird die Referenz für den Entwicklungszweig gelöscht (möglicherweise müssen Sie auch alle Dateien löschen, die Sie für diesen Zweig bereitgestellt haben). Anschließend können git push deploy_localtest developSie den gewünschten Push-Befehl für diesen Zweig ausführen.

Lehm
quelle