So machen Sie einen Git-Commit rückgängig –amend [duplicate]

Lesezeit: 6 Minuten

Benutzer-Avatar
Jwan622

Ich habe versehentlich ein git commit –amend eingegeben. Das ist ein Fehler, weil mir klar wurde, dass der Commit eigentlich völlig neu ist und mit einer neuen Nachricht festgeschrieben werden sollte. Ich möchte einen neuen Commit machen. Wie mache ich das rückgängig?

  • git reset --soft @{1}

    – Benutzer4003407

    23. Juni 2016 um 20:20 Uhr


  • git reset --soft @{1} funktioniert bei mir nicht. Ich mache einfach das Commit rückgängig und zerquetsche sie dann. dieses Problem gelöst.

    – Zhang

    16. Mai 2019 um 6:23 Uhr


  • Die Wiederholung dieser Frage führte zu noch besseren Informationen, um es nur so zu sagen

    – Jwan622

    15. Juli 2021 um 19:59 Uhr

Benutzer-Avatar
Torek

Der Kommentar von PetSerAl ist der Schlüssel. Hier sind die beiden Befehlssequenzen, um genau das zu tun, was Sie wollen:

git reset --soft @{1}
git commit -C @{1}

und eine Erklärung, wie das funktioniert.

Beschreibung

Wenn Sie ein neues Commit machen, ist Git normalerweise1 verwendet diese Abfolge von Ereignissen:

  1. Lesen Sie die ID (SHA-1-Hash, wie z a123456...) des aktuellen Commits (via HEAD, was uns den aktuellen Zweig gibt). Nennen wir diese ID C (für Strom). Beachten Sie, dass dieser aktuelle Commit einen übergeordneten Commit hat; nennen wir seine ID P (für Eltern).
  2. Verwandeln Sie den Index (auch Staging-Bereich genannt) in einen Baum. Dies erzeugt eine andere ID; nennen wir diese ID T (für Baum).
  3. Schreiben Sie einen neuen Commit mit parent = C und Baum = T. Dieser neue Commit erhält eine andere ID. Nennen wir das N (für neue).
  4. Aktualisieren Sie den Branch mit der neuen Commit-ID N.

Beim Benutzen --amend Git ändert den Prozess ein wenig. Es schreibt immer noch wie zuvor einen neuen Commit, aber in Schritt 3, anstatt den neuen Commit mit parent = zu schreiben Ces schreibt es mit parent = P.

Bild

Bildlich können wir nachzeichnen, was so geschah. Wir beginnen mit einem Commit-Graphen, der auf endet P--Cwies darauf hin branch:

...--P--C   <-- branch

Wenn wir das neue Commit machen N wir bekommen:

...--P--C--N   <-- branch

Wenn wir verwenden --amenderhalten wir stattdessen Folgendes:

       C
      /
...--P--N   <-- branch

Beachten Sie dieses Commit C ist noch im Depot; es wurde einfach beiseite geschoben, aus dem Weg, also dieser neue Commit N kann auf den alten Elternteil zurückweisen P.

Tor

Was du dir gemerkt hast wollennach dem git commit --amendsoll die Kette stattdessen so aussehen:

...--P--C--N   <-- branch

Wir können nicht ziemlich Tun Sie dies – wir können uns nicht ändern N; Git kann sich nie ändern irgendein commit (oder ein anderes Objekt), sobald es im Repo gespeichert ist – aber beachten Sie, dass die ...--P--C Kette ist noch drin, völlig intakt. Commit finden Sie C durch die Reflogs, und das ist, was die @{1} Syntax tut. (Insbesondere ist dies die Abkürzung für currentbranch@{1},2 was bedeutet „wo currentbranch zeigte vor einem Schritt”, was “begehen” war C“.)

Also laufen wir jetzt git reset --soft @{1}was dies tut:

       C   <-- branch
      /
...--P--N

Jetzt branch verweist auf Cder auf zurück weist P.

Was passiert mit N? Das gleiche, was passiert ist C vorher: es wird für eine Weile durch das Reflog gespeichert.

Wir brauchen es nicht wirklich (obwohl es nützlich sein kann), weil die --soft Flagge zu git reset lässt den Index / Staging-Bereich unberührt (zusammen mit dem Arbeitsbaum). Das bedeutet, dass wir jetzt wieder einen neuen Commit machen können, indem wir einfach einen anderen ausführen git commit. Es durchläuft die gleichen vier Schritte (Lesen Sie die ID aus HEADerstellen Sie den Baum, erstellen Sie ein neues Commit und aktualisieren Sie den Zweig):

       C--N2   <-- branch
      /
...--P--N

wo N2 wird unser neues neues (zweites neues?) Commit sein.

Wir können sogar machen git commit Verwenden Sie die Commit-Nachricht von Commit erneut N. Das git commit Befehl hat a --reuse-message Argument, auch buchstabiert -C; alles, was wir tun müssen, ist, ihm etwas zu geben, das ihn das ursprüngliche neue Commit finden lässt N von dem die Nachricht kopiert werden soll, zu machen N2 mit. Wie machen wir das? Die Antwort lautet: Es steht genauso im Reflog C war, als wir das tun mussten git reset.

Tatsächlich ist es dasselbe @{1}!

Denken Sie daran, @{1} bedeutet “wo es gerade war” und git reset habe es gerade aktualisiert und verschoben C zu N. Wir noch nicht gemacht neues Commitment N2. (Sobald wir das tun, N wird sein @{2}haben wir aber noch nicht.)

Wenn wir also alles zusammenfassen, erhalten wir:

git reset --soft @{1}
git commit -C @{1}

1Die Stellen, an denen diese Beschreibung aufschlüsselt, beinhalten, wenn Sie eine Zusammenführung ändern, wenn Sie sich auf einem getrennten HEAD befinden und wenn Sie einen alternativen Index verwenden. Aber selbst dann ist es ziemlich offensichtlich, wie man die Beschreibung ändert.

2Wenn HEAD freistehend ist, so dass dort ist kein Stromzweig, die Bedeutung wird HEAD@{1}. Beachten Sie, dass @ an sich ist kurz für HEADalso die Tatsache, dass @{n} bezieht sich eher auf den aktuellen Zweig als auf HEAD selbst, ist ein bisschen inkonsistent.

Um zu sehen, wie sie sich unterscheiden, betrachten Sie git checkout develop gefolgt von git checkout master (vorausgesetzt, beide Zweige existieren). Der Erste checkout Änderungen HEAD deuten auf developund die zweite ändert sich HEAD deuten auf master. Das bedeutet, dass master@{1} ist was auch immer verpflichten master wies darauf hin, vor dem letzten Update auf master; aber HEAD@{1} ist die Verpflichtung develop zeigt auf jetzt – wahrscheinlich irgendein anderes Commit.

(Zusammenfassung: nach diesen beiden git checkout Befehle, @{1} meint master@{1} jetzt, HEAD@{1} bedeutet das gleiche Commit wie develop jetzt und @ meint HEAD. Wenn Sie verwirrt sind, nun, ich war es auch, und anscheinend bin ich nicht allein: Siehe die Kommentare.)

  • SO VIEL ICH WEISS, @{1} ist kurz für currentbranch@{1} nicht HEAD@{1}.

    – Benutzer4003407

    23. Juni 2016 um 22:49 Uhr

  • @PetSerAl: Aha, du hast Recht! Wenn HEAD jedoch getrennt ist, funktioniert es als HEAD@{1}. Dies scheint seither etwas inkonsistent @ meint HEADaber ich vermute HEAD@{0} und currentbranch@{0} sind auch unbedingt notwendig, wenn es überhaupt einen Stromzweig gibt. Danke, ich werde die Antwort korrigieren.

    – Torek

    23. Juni 2016 um 23:17 Uhr


  • @andrybak: teste es durch Bewegen HEAD und/oder einige Äste ein paar Mal, HEAD lösen, etwas mehr bewegen und wieder anbringen. Die Semantik ist komplizierter als die Syntax.

    – Torek

    23. Juni 2016 um 23:32 Uhr

  • @andrybak Trotzdem HEAD ist eine symbolische Referenz, @{1} und @@{1} unterschiedliche Bedeutung haben.

    – Benutzer4003407

    23. Juni 2016 um 23:35 Uhr


  • @8bitjunkie: Nicht einfach blind verwenden @{1} denn wenn Sie etwas getan haben seit das git commit --amendes wird nicht sein 1 mehr. Laufen git reflog bei Bedarf, um die richtige Hash-ID oder Nummer für die zu finden @{...} Syntax.

    – Torek

    12. Oktober 2020 um 20:26 Uhr

1300940cookie-checkSo machen Sie einen Git-Commit rückgängig –amend [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy