Kann git pre-receive hooks den eingehenden Commit auswerten?

8

Ich versuche, einen serverseitigen Pre-Receive-Git-Hook zu schreiben, um Commits zu bewerten, wenn sie gepusht werden.

Nach den Antworten hier , dies sollte leicht möglich sein, indem ich git log suchen und herausfiltern, was ich mit 'format:' will.

Ich habe das folgende vorbereitende Skript erstellt.

%Vor%

Ich finde, wenn ich git show oder git log auf dem Server starte, sind die Ergebnisse für den aktuellen HEAD, während ich das eingehende Commit abfragen möchte .

Wie kann ich dieses Skript ändern, um git log oder git show für den noch nicht erhaltenen Commit auszuführen?

    
spuder 20.03.2014, 22:20
quelle

1 Antwort

17

Sie müssen die SHA-1-IDs verwenden, die an der Standardeingabe bereitgestellt werden:

%Vor%

Der "Testcode" muss dann mindestens einige und vielleicht alle drei Elemente anzeigen, abhängig von den auszuführenden Tests.

Der Wert in $oldsha ist 40 0 s, wenn vorgeschlagen wird, dass der Referenzname $refname erstellt wird. Das heißt, $refname (normalerweise so etwas wie refs/heads/master oder refs/tags/v1.2 , aber jeder Name in refs/ kann erscheinen: refs/notes/commits zum Beispiel) existiert jetzt nicht im empfangenden Repository, wird aber existieren und zeigen zu $newsha , wenn Sie die Änderung zulassen.

Der Wert in $newsha ist 40 0 s, wenn vorgeschlagen wird, den Referenznamen $refname zu löschen. Das heißt, $refname existiert jetzt und zeigt auf das Objekt $oldsha ; Wenn Sie die Änderung zulassen, wird dieser Referenzname gelöscht.

Die Werte beider Werte sind ungleich Null, wenn der Referenzname $refname zur Aktualisierung vorgeschlagen wird, dh er zeigt momentan auf das Objekt $oldsha . Wenn Sie die Änderung zulassen, wird auf das neue Objekt% verwiesen. stattdessen co_de%.

Wenn Sie einfach $newsha oder git log ausführen, verwendet git den gefundenen SHA-1, indem Sie git show ausführen. In einem typischen Empfangs-Repository ist git rev-parse HEAD eine symbolische Referenz, die auf HEAD verweist (die Datei refs/heads/master enthält buchstäblich die Zeichenkette HEAD ), sodass Sie das oberste Commit auf dem Zweig ref: refs/heads/master (wie Sie) sehen beobachtet).

Sie müssen sich genau anschauen, welche neuen Objekte hereinkommen. Woher wissen Sie, welche neuen Objekte hereinkommen? Das hängt davon ab, was mit den angegebenen master und möglicherweise anderen ref-Namen passiert.

Wenn der refname gelöscht werden soll, kommt nichts neues hinzu. Ob irgendwelche zugrundeliegenden git Objekte gelöscht werden (Garbage collected) hängt davon ab, ob dieser Refname der "letzte" Verweis auf diese Objekte ist . Nehmen Sie zum Beispiel an, dass die gesamte Standard-Eingabesequenz aus zwei Direktiven besteht:

  • löschen $refname
  • löschen refs/heads/foo

Nehmen wir weiter an, dass refs/tags/v1.1 (Zweig refs/heads/foo ) auf commit foo in diesem Grafikdiagramm verweist und% F auf das mit Anmerkungen versehene Tag v1.1 :

verweist %Vor%

Das Löschen der Verzweigung G ist "sicher", da keine Commits weggehen, weil das mit Anmerkungen versehene Tag foo sie über das G -Tag behalten wird.

Löschen des Tags v1.1 ist "sicher" (ish), da keine Commits weggehen, weil die Verzweigung v1.1 sie über den Verweis foo behält. (Das annotierte Tag-Objekt selbst wird verschwinden. Es liegt an Ihnen, ob Sie dies zulassen)

Das Löschen von beide ist jedoch nicht sicher: commits refs/heads/foo und E werden nicht erreichbar und werden gesammelt. (Es liegt an Ihnen, ob Sie das trotzdem zulassen.)

Andererseits ist es möglich, dass stdin neben diesen beiden Direktiven eine dritte Direktive enthält:

  • create F zeigt auf commit refs/heads/foo2 , mit commit H zeigt auf commit H als übergeordnetem [ Bearbeiten: Beim nochmaligen Lesen bemerke ich die grelle Annahme, dass G ist ein Commit-Objekt und kein Tag-Objekt. Wenn wir annehmen, dass G ein Commit-Objekt ist, ist der Rest des Folgenden korrekt, aber das obige wird zumindest ein bisschen falsch. Die allgemeine Idee, dass die DAG durch externe Referenzen geschützt wird, ist jedoch immer noch richtig, und das sollte meist sinnvoll sein. ]

In diesem Fall ist die Löschung von G sicher, da der neue Zweig foo weiterhin commit foo2 beibehält, wodurch commit H beibehalten wird.

Eine vollständige Analyse ist schwierig; es ist oft besser, nur eine stückweise Analyse durchzuführen, die "sichere" Operationen erlaubt (was auch immer Sie sich entscheiden) und Benutzer dazu zwingen, die Aktualisierungen stückweise auf "sichere" Weise zu pushen (Zweig G zuerst erstellen und dann Zweig% löschen co_de% zum Beispiel als separaten Push).

Wenn Sie nur neue Commits anzeigen möchten, dann für jedes Referenzupdate:

  • Wenn es ein Löschen ist, erlauben Sie es (oder verwenden Sie andere Regeln).
  • Wenn es sich um ein Erstellen oder eine Änderung handelt, suchen Sie nach erreichbaren Commit-Objekten, die zuvor nicht erreichbar waren, und prüfen Sie diese Commits.

In den meisten "normalen" Pre-Receive-Hooks würden Sie die unten beschriebenen Methoden verwenden, aber wir haben eine Alternative für diese spezielle Aufgabe.

Es gibt eine Abkürzung für Änderungen, die die häufigsten und meist interessantesten Fälle behandelt. Angenommen jemand schlägt vor, foo2 von foo auf refs/heads/foo zu aktualisieren. Es ist möglich, dass einige Objekte in dem Bereich bereits vorhanden waren, z. B. 1234567... ist die ID von commit 9876543... und 1234567 ist die ID von commit C :

%Vor%

In diesem Fall werden die Objekte D und E untersucht. Dies gilt auch, wenn die Commits 9876543 und E gerade hochgeladen wurden, aber no Referenzen haben, dh das vorgeschlagene Update ist um D und E hinzuzufügen und das Diagramm sieht jetzt so aus:

%Vor%

In jedem Fall ein einfaches:

%Vor%

erzeugt die Objekt-IDs, die Sie betrachten sollten.

Für neue Referenzen gibt es keine Abkürzung. Angenommen, wir haben die gleichen fünf Commits, die oben gezeigt wurden, mit demselben D , aber keinem E , und der tatsächliche Vorschlag lautet "create refs/heads/foo zeigt auf refs/heads/bar ". In diesem Fall sollten wir uns erneut die Commits refs/heads/bar und E ansehen, aber es gibt keine offensichtliche Möglichkeit, über D zu erfahren.

Der nicht naheliegende Weg, der nur in einigen Fällen funktioniert, ist das Finden von Objekten, die bei der vorgeschlagenen Erstellung erreichbar sind, die derzeit überhaupt nicht erreichbar sind:

%Vor%

In diesem speziellen Fall werden die IDs für E und D erneut erzeugt.

Sehen wir uns jetzt Ihren speziellen Fall an, in dem Sie sich alle Commits anschauen möchten, die vorgeschlagen werden. Hier ist eine Möglichkeit, dies zu bewältigen.

Für alle vorgeschlagenen Updates:

  • Wenn dies ein Löschvorgang ist, haben wir einige Löschungen.
  • Wenn es sich um ein Create oder Update handelt, haben wir einige neue Commits; akkumulieren die neue SHA.

Wenn wir einige Löschungen haben und haben wir einige SHAs angesammelt, lehnen den Versuch ab: es ist zu schwer. Lassen Sie den Benutzer die Vorgänge trennen.

Andernfalls, wenn wir keine angesammelten SHAs haben, müssen wir nur löschen (oder vielleicht gar nichts - sollte nicht passieren, aber harmlos); erlaube dies (exit 0).

Ansonsten müssen wir einige neue SHA-1-Werte haben.

Unter Verwendung der vorgeschlagenen neuen SHAs als Startpunkte finden Sie alle git-Objekte, die erreichbar wären, ausgenommen alle Objekte, die derzeit unter einem beliebigen Namen erreichbar sind. Dies sind alle neuen Objekte.

Untersuchen Sie für jeden, der ein Commit ist, ob es verboten ist. Wenn dies der Fall ist, lehnen Sie die gesamte Operation ab (auch wenn einige Teile erfolgreich sein könnten); Wie zuvor ist es zu schwer, dies herauszufinden, also lassen Sie den Benutzer die "guten" Operationen von den "schlechten" unterscheiden.

Wenn wir so weit kommen, ist alles in Ordnung; Erlaube das gesamte Update.

In Codeform:

%Vor%     
torek 20.03.2014, 23:35
quelle

Tags und Links