So machen Sie "git commit --amend" rückgängig, anstatt "git commit"

1295

Ich habe versehentlich mein vorheriges Commit geändert. Das Commit sollte separat sein, um den Verlauf der Änderungen zu speichern, die ich an einer bestimmten Datei vorgenommen habe.

Gibt es eine Möglichkeit, dieses letzte Commit rückgängig zu machen? Wenn ich so etwas mache git reset --hard HEAD^, wird auch das erste Commit rückgängig gemacht.

(Ich habe noch keine Remote-Verzeichnisse verschoben)

Jesper Rønn-Jensen
quelle

Antworten:

2291

Sie müssen lediglich ein neues Commit mit denselben Details wie das aktuelle HEADCommit erstellen , jedoch mit dem übergeordneten Commit als vorherige Version von HEAD. git reset --softVerschiebt den Verzweigungszeiger so, dass das nächste Festschreiben über einem anderen Festschreiben erfolgt als der aktuelle Verzweigungskopf.

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}
CB Bailey
quelle
33
Sehr cool, +1. Ich habe es sogar mit der vorletzten Änderungsansicht gemacht git reflog, um die richtige Nummer zu finden, z {2}.
JJD
179
Um ganz klar zu sein, der erste Befehl ist ein echtes "Rückgängigmachen". Es erzeugt den HEAD, das Arbeitsverzeichnis (unverändert) und den Indexstatus vor git commit --amend. Das zweite ist ein "Wiederherstellen" eines neuen Commits. Diese funktionieren für jeden git commit, nicht nur --amend.
cdunn2001
60
Wenn Sie also keine neue Commit-Nachricht geändert haben, die Sie retten müssen, kann der zweite Teil nur ein regulärer Teil sein git commit.
Matt Montag
18
Aus irgendeinem Grund wurde beim Ausführen ein Fehler angezeigt git reset --soft HEAD@{1}: fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions. Als ich durch HEAD@{1}den in git reflog(danke JJD!) Gezeigten entsprechenden Commit-Hash ersetzt habe , hat diese Antwort wunderbar funktioniert!
Tim Camber
20
@ TimArnold Abhängig von Ihrer Shell müssen Sie möglicherweise einfache oder doppelte Anführungszeichen setzen HEAD@{1}. Wenn ich echo HEAD@{1}zum Beispiel in tcsh laufe , liegt die Ausgabe HEAD@1daran, dass die geschweiften Klammern von tcsh interpretiert wurden. Wenn ich einfache Anführungszeichen verwende, bleiben die geschweiften Klammern erhalten.
Kelvin
136

Verwenden Sie das Ref-Protokoll :

git branch fixing-things HEAD@{1}
git reset fixing-things

Sie sollten dann alle zuvor geänderten Änderungen nur in Ihrer Arbeitskopie haben und können sie erneut festschreiben

um eine vollständige Liste der vorherigen Indizes anzuzeigen git reflog

stricken
quelle
7
Dies löscht auch den Index - immer noch nützlich, geht aber über ein einfaches "Rückgängigmachen" hinaus.
cdunn2001
3
Gibt es einen Unterschied zwischen HEAD@{1}und HEAD~1?
Neaumusic
15
@neaumusic: ja! HEAD~1ist genau das gleiche wie HEAD^und kennzeichnet das übergeordnete Element des aktuellen Commits. HEAD@{1}Auf der anderen Seite bezieht sich dies auf das Commit, auf das HEAD vor diesem Commit hingewiesen hat, dh es bedeutet unterschiedliche Commits, wenn Sie einen anderen Zweig auschecken oder ein Commit ändern.
Knittl
@ Knittl ah kein Wunder, ich dachte nicht, dass dies möglich war, bevor ich mich noch einmal bedanke, gute Informationen
neaumusic
9
Der erste Schritt ist überflüssig. Einfach git reset HEAD@{1}ist genug.
Dwelle
79

Finden Sie Ihre geänderten Commits durch:

git log --reflog

Hinweis: Sie können hinzufügen --patch, um den Hauptteil der Commits der Übersichtlichkeit halber anzuzeigen. Gleich wie git reflog.

Setzen Sie dann Ihren HEAD an dem Punkt auf ein vorheriges Commit zurück, an dem es in Ordnung war durch:

git reset SHA1 --hard

Hinweis: Ersetzen Sie SHA1 durch Ihren echten Commit-Hash. Beachten Sie auch, dass dieser Befehl alle nicht festgeschriebenen Änderungen verliert , sodass Sie sie möglicherweise vorher aufbewahren können. Alternativ verwendet --softstattdessen die neuesten Änderungen zu behalten und sie dann begehen.

Wählen Sie dann das andere Commit aus, das Sie zusätzlich benötigen:

git cherry-pick SHA1
Kenorb
quelle
26
In diesem Fall können Sie git reset SHA1 --softdie neuesten Änderungen beibehalten und anschließend festschreiben.
Pravj
24

Sie können ein Commit jederzeit aus dem Handbuch aufteilen

  • Starten Sie eine interaktive Rebase mit git rebase -i commit ^, wobei commit das Commit ist, das Sie teilen möchten. Tatsächlich reicht jeder Festschreibungsbereich aus, solange er dieses Festschreiben enthält.
  • Markieren Sie das Commit, das Sie teilen möchten, mit der Aktion "Bearbeiten".
  • Wenn Sie dieses Commit bearbeiten möchten, führen Sie git reset HEAD ^ aus. Der Effekt ist, dass der KOPF um eins zurückgespult wird und der Index folgt. Der Arbeitsbaum bleibt jedoch gleich.
  • Fügen Sie nun die Änderungen zu dem Index hinzu, den Sie beim ersten Festschreiben haben möchten. Sie können dazu git add (möglicherweise interaktiv) oder git-gui (oder beides) verwenden.
  • Übernehmen Sie den aktuellen Index mit der jeweils geeigneten Festschreibungsnachricht.
  • Wiederholen Sie die letzten beiden Schritte, bis Ihr Arbeitsbaum sauber ist.
  • Setzen Sie die Rebase mit Git Rebase fort - weiter.
Arkaitz Jimenez
quelle
26
viel zu kompliziert. git reflogist alles was Sie brauchen
knittl
2
Viele Schritte ja, aber jeder Schritt ist unkompliziert und einfach durchzuführen. Das hat bei mir funktioniert und bekommt meine Stimme.
OzBandit
5
Darüber hinaus können Sie mit dieser Antwort selektiv die Änderungen auswählen, die Sie versehentlich "geändert" haben, um dem git reset --soft HEAD @ {1} -Ansatz (der mein Problem
übrigens
2
Sie können Änderungen auch mit der Reflog-Methode selektiv auswählen. Einfach git resetstatt statt git reset --soft, dann tun git add --patch.
Geekofalltrades
1
Dies schreibt die Geschichte immer noch neu und erfordert einen Force Push. Abhängig von Ihrer Situation kann dies ein Problem sein oder auch nicht.
Pajn
20

Möglicherweise sollten Sie beachten, dass Sie die Festschreibungsnachricht löschen können, wenn Sie sich noch in Ihrem Editor mit der Festschreibungsnachricht befinden. Dadurch wird der git commit --amendBefehl abgebrochen .

Justin Schulz
quelle
Das ist die eine.
Atilkan
Gespeichert meine aber ^^
Engineercoding
14

Vielleicht kann verwendet werden git reflog, um zwei Commits vor und nach der Änderung zu erhalten.

Verwenden Sie dann git diff before_commit_id after_commit_id > d.diff, um den Unterschied zwischen vor und nach der Änderung zu ermitteln.

Weiter verwenden git checkout before_commit_id, um vor dem Festschreiben zurückzukehren

Und zuletzt verwenden Sie git apply d.diff, um die tatsächliche Änderung anzuwenden, die Sie vorgenommen haben.

Das löst mein Problem.

utzcoz
quelle
11

Wenn Sie das Commit auf Remote verschoben und dann Änderungen an diesem Commit fälschlicherweise geändert haben, wird Ihr Problem behoben. Geben Sie a aus git log, um die SHA vor dem Festschreiben zu finden. (Dies setzt voraus, dass Remote als Ursprung bezeichnet wird). Geben Sie nun diesen Befehl mit diesem SHA aus.

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit
David Sopko
quelle
3
Dies ist ein Sonderfall der allgemeineren Frage, aber er deckte genau meinen unmittelbaren Bedarf ab.
dmckee --- Ex-Moderator Kätzchen
8

Sie können unten tun, um Ihre rückgängig zu machen git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

===================================

Jetzt sind Ihre Änderungen wie zuvor. Damit sind Sie mit dem Rückgängigmachen für fertiggit commit —amend

Jetzt können Sie tun git push origin <your_branch_name>, um zum Zweig zu schieben.

Pratik
quelle
3

Fast 9 Jahre zu spät, aber diese Variante wurde nicht erwähnt, um dasselbe zu erreichen (es ist eine Art Kombination aus einigen davon, ähnlich der Top-Antwort ( https://stackoverflow.com/a/1459264/4642530 ). .

Durchsuche alle abgetrennten Köpfe auf dem Ast

git reflog show origin/BRANCH_NAME --date=relative

Dann finden Sie den SHA1-Hash

Auf alten SHA1 zurücksetzen

git reset --hard SHA1

Dann schieben Sie es wieder nach oben.

git push origin BRANCH_NAME

Erledigt.

Dadurch kehren Sie vollständig zum alten Commit zurück.

(Einschließlich des Datums des zuvor überschriebenen, losgelösten Commit-Kopfes)

Garrettmac
quelle
Ja, aber ich möchte normalerweise zurücksetzen --soft, um meine Änderungen beizubehalten. Ich möchte es nur separat
Juan Mendes
2
  1. Kasse zum temporären Zweig mit letztem Commit

    git branch temp HEAD@{1}

  2. Letztes Commit zurücksetzen

    git reset temp

  3. Jetzt haben Sie alle Dateien, die Sie festschreiben, sowie die vorherigen Festschreibungen. Überprüfen Sie den Status aller Dateien.

    git status

  4. Setzen Sie Ihre Commit-Dateien von der Git-Phase zurück.

    git reset myfile1.js (bald)

  5. Bringen Sie dieses Commit wieder an

    git commit -C HEAD@{1}

  6. Fügen Sie Ihre Dateien hinzu und übergeben Sie sie einem neuen Commit.

Priyanshu Chauhan
quelle