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?
So machen Sie einen Git-Commit rückgängig –amend [duplicate]
Jwan622
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:
- Lesen Sie die ID (SHA-1-Hash, wie z
a123456...
) des aktuellen Commits (viaHEAD
, 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). - Verwandeln Sie den Index (auch Staging-Bereich genannt) in einen Baum. Dies erzeugt eine andere ID; nennen wir diese ID T (für Baum).
- 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).
- 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--C
wies darauf hin branch
:
...--P--C <-- branch
Wenn wir das neue Commit machen N
wir bekommen:
...--P--C--N <-- branch
Wenn wir verwenden --amend
erhalten 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 --amend
soll 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 C
der 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 HEAD
erstellen 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 HEAD
also 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 develop
und 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ürcurrentbranch@{1}
nichtHEAD@{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@
meintHEAD
aber ich vermuteHEAD@{0}
undcurrentbranch@{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 dasgit commit --amend
es wird nicht sein1
mehr. Laufengit reflog
bei Bedarf, um die richtige Hash-ID oder Nummer für die zu finden@{...}
Syntax.– Torek
12. Oktober 2020 um 20:26 Uhr
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