Rückgängigmachen einer Git-Rebase

3179

Wie kann ich eine Git-Rebase einfach rückgängig machen?

Meine aktuellen Ideen sind nur manuelle Ansätze:

  1. git checkout auf dem Commit-Elternteil für beide Zweige
  2. Erstellen Sie von dort aus einen temporären Zweig
  3. git cherry-pick alle Commits von Hand
  4. Ersetzen Sie den Zweig, in dem ich neu basiert habe, durch den manuell erstellten Zweig

In meiner aktuellen Situation würde dies funktionieren, da ich Commits aus beiden Zweigen leicht erkennen kann (einer war mein Zeug, der andere war das Zeug meines Kollegen).

Mein Ansatz erscheint mir jedoch suboptimal und fehleranfällig (sagen wir, ich habe gerade mit 2 meiner eigenen Zweige neu basiert).

Klarstellung : Ich spreche von einer Rebase, bei der eine Reihe von Commits wiederholt wurden. Nicht nur einer.

Webmat
quelle
6
Beachten Sie auch, dass Sie während einer Rebase Commits ausschließen oder sie quetschen können. Diese Änderungen können nicht zurückgesetzt werden, ohne dass ein Zeiger auf die ursprünglichen Knoten vorhanden ist oder das Reflog durchsucht wird, sodass das Cherrypicking nicht funktioniert.
ANeves

Antworten:

4337

Der einfachste Weg wäre, das Head-Commit des Zweigs zu finden, wie es unmittelbar vor dem Start der Rebase im Reflog war ...

git reflog

und um den aktuellen Zweig darauf zurückzusetzen (mit den üblichen Einschränkungen, dass Sie vor dem Zurücksetzen mit der --hardOption absolut sicher sind ).

Angenommen, das alte Commit befand sich HEAD@{5}im Referenzprotokoll:

git reset --hard HEAD@{5}

In Windows müssen Sie möglicherweise die Referenz angeben:

git reset --hard "HEAD@{5}"

Sie können den Verlauf des alten Kopfes des Kandidaten überprüfen, indem Sie einfach ein git log HEAD@{5}( Windows :) ausführengit log "HEAD@{5}" .

Wenn Sie nicht pro Zweig-Reflogs deaktiviert haben, sollten Sie dies einfach tun können, git reflog branchname@{1}da eine Rebase den Zweigkopf abtrennt, bevor Sie ihn wieder an den endgültigen Kopf anschließen. Ich würde dies jedoch noch einmal überprüfen, da ich dies kürzlich nicht überprüft habe.

Standardmäßig sind alle Reflogs für nicht nackte Repositorys aktiviert:

[core]
    logAllRefUpdates = true
CB Bailey
quelle
115
Git Reflog ist fantastisch, denken Sie daran, dass Sie mit git log -g(Tipp von Scott Chacons progit.org/book ) eine besser formatierte Ausgabe erhalten können .
Karmi
60
@Zach: git rebase --abort( -imacht keinen Sinn mit --abort) dient dazu, eine nicht abgeschlossene Rebase aufzugeben - entweder weil es Konflikte gab oder weil sie interaktiv war oder beides; Es geht nicht darum, eine erfolgreiche Rebase rückgängig zu machen, worum es bei der Frage geht. Sie würden entweder verwenden rebase --abortoder reset --hardabhängig davon, in welcher Situation Sie sich befanden. Sie sollten nicht beides tun müssen.
CB Bailey
311
Nur für den Fall, machen Sie zuerst ein Backup : git tag BACKUP. Sie können darauf zurückkommen, wenn etwas schief geht:git reset --hard BACKUP
kolypto
6
Wenn Sie viele Commits gemacht haben, wird dem von Ihnen gesuchten HEAD @ {#} commit:im Gegensatz zu vorangestellt rebase:. Klingt offensichtlich, hat mich aber ein bisschen verwirrt.
Warpling
4
Beitritt zur Party nach einer versehentlichen Rebase: D. Würde a git reset --hard ORIG_HEADden Trick nicht auch sofort nach dem versehentlichen Rebase machen?
Quaylar
1487

Tatsächlich speichert Rebase Ihren Ausgangspunkt, ORIG_HEADsodass dies normalerweise so einfach ist wie:

git reset --hard ORIG_HEAD

Doch das reset, rebaseund mergealle speichern Ihre ursprüngliche HEADZeiger in dem ORIG_HEADso ist , wenn Sie noch eine dieser Befehle durchgeführt , da die rebase Sie rückgängig machen sind versuchen , dann werden Sie die reflog verwenden.

Pat Notz
quelle
34
Falls dies ORIG_HEADnicht mehr sinnvoll ist, können Sie auch die branchName@{n}Syntax verwenden, wobei ndie n-te vorherige Position des Verzweigungszeigers ist. Wenn Sie beispielsweise die featureAVerzweigung auf Ihre masterVerzweigung neu stützen, das Ergebnis der Neubasis jedoch nicht gefällt, können Sie git reset --hard featureA@{1}die Verzweigung einfach auf den genauen Stand zurücksetzen, an dem sie sich vor der Neubasis befand. Weitere Informationen zur branch @ {n} -Syntax finden Sie in den offiziellen Git-Dokumenten für Überarbeitungen .
15
Das ist am einfachsten. Folgen Sie ihm mit einem git rebase --abortobwohl.
Seph
1
@DaBlick das hat bei mir nach einer völlig erfolgreichen Rebase ohne Konflikte gut funktioniert git 2.17.0.
dvlsg
4
Und lassen Sie es mich ergänzen: git reset --hard ORIG_HEADKann wiederholt verwenden, um immer wieder zurückzurollen. Sagen wir, wenn A --- Rebase zu --- B --- Rebase zu --- C, jetzt bin ich bei C, kann ich zweimal zu A zurückkehrengit reset --hard ORIG_HEAD
CalvinChe
5
@Seph Kannst du erklären, warum du vorschlägst, mit zu folgen git rebase --abort?
UpTheCreek
386

Charles 'Antwort funktioniert, aber vielleicht möchten Sie dies tun:

git rebase --abort

nach dem aufräumen reset.

Andernfalls erhalten Sie möglicherweise die Meldung " Interactive rebase already started".

Allan
quelle
4
Dieser hat den Teil "| REBASE" in meiner Eingabeaufforderung entfernt. +1
Wouter Thielen
62
Das war nicht die Frage. In der Frage wird gefragt, wie eine fertige Rebase rückgängig gemacht werden kann.
Arunav Sanyal
2
Sollte ein Kommentar zu Charles Antwort sein, da er die Frage nicht beantwortet
Murmel
Hm, das musste ich nicht machen.
Viktor Seč
1
Der einzige, der für mich funktioniert hat!
Alexandre Picard
90

Das Zurücksetzen des Zweigs auf das baumelnde Festschreibungsobjekt seiner alten Spitze ist natürlich die beste Lösung, da der vorherige Zustand ohne großen Aufwand wiederhergestellt wird. Wenn Sie diese Commits jedoch verloren haben (z. B. weil Sie in der Zwischenzeit Ihr Repository mit Müll gesammelt haben oder dies ein neuer Klon ist), können Sie den Zweig jederzeit erneut neu starten. Der Schlüssel dazu ist der --ontoSchalter.

Angenommen , Sie haben ein Thema Zweig hatte phantasievoll genannt topic, dass Sie abgezweigt , masterwenn die Spitze masterder war zu 0deadbeefbegehen. Irgendwann auf dem topicAst hast du es getan git rebase master. Jetzt möchten Sie dies rückgängig machen. Hier ist wie:

git rebase --onto 0deadbeef master topic

Dadurch werden alle topicnicht masteraktivierten Commits übernommen und zusätzlich wiedergegeben 0deadbeef.

Mit --ontokönnen Sie Ihre Geschichte in nahezu jede Form umwandeln .

Habe Spaß. :-)

Aristoteles Pagaltzis
quelle
3
Ich denke, dies ist aufgrund seiner Flexibilität die beste Option. Ich habe b1 vom Master verzweigt, dann b1 in einen neuen Zweig b2 umbasiert und wollte dann b1 zurücksetzen, um wieder auf dem Master zu basieren. Ich liebe Git einfach - danke!
Ripper234
2
Dies ist die beste Option hier! Es hat alle Änderungen, die ich an meinem aktuellen Zweig habe, beibehalten und alle unerwünschten entfernt!
Alicia Tang
Ich würde sagen, dass Sie mit einer Kombination aus --ontound -iSie Ihre Geschichte in so ziemlich jede Form neu ordnen können. Verwenden Sie gitk (oder gitx auf dem Mac), um die Formen zu sehen, die Sie erstellen :-).
rjmunro
69

Ich habe tatsächlich ein Backup-Tag in den Zweig eingefügt, bevor ich eine nicht triviale Operation ausführe (die meisten Rebases sind trivial, aber ich würde das tun, wenn es irgendwo komplex aussieht).

Dann ist das Wiederherstellen so einfach wie git reset --hard BACKUP.

Alex Gontmakher
quelle
2
Ich mache das auch Es ist auch nützlich, diff BACKUP..HEAD zu verwenden, um sicherzustellen, dass Sie geändert haben, was Sie gemeint haben.
Paul Bone
5
Früher habe ich das auch gemacht, aber seit ich mich mit dem Reflog besser vertraut gemacht habe, halte ich es nicht mehr für notwendig. Das Reflog tut dies im Wesentlichen jedes Mal in Ihrem Namen, wenn Sie HEAD wechseln.
Pete Hodgson
4
Nun, ich bevorzuge aussagekräftige Namen, weil die Suche nach dem richtigen Element im Reflog manchmal überhaupt keinen Spaß macht.
Alex Gontmakher
12
Sie müssen nicht einmal einen Sicherungszweig erstellen, sondern können einfach die branchName@{n}Syntax verwenden. Hier nist die n-te vorherige Position des Verzweigungszeigers. Wenn Sie beispielsweise die featureAVerzweigung auf Ihre masterVerzweigung neu stützen, das Ergebnis der Neubasis jedoch nicht gefällt, können Sie git reset --hard featureA@{1}die Verzweigung einfach auf den genauen Stand zurücksetzen, an dem sie sich vor der Neubasis befand. Weitere Informationen zurbranch@{n} Syntax finden Sie in den offiziellen Git-Dokumenten für Überarbeitungen .
2
Tatsächlich müssen Sie nicht einmal die obige Syntax verwenden, laut Pat Notz 'Antwort wird das Original HEADdes Zweigs vorübergehend in gespeichert ORIG_HEAD. Aber die Technik der Verwendung eines Backup-Zweigetiketts funktioniert auch, es sind nur mehr Schritte.
68

Für den Fall , Sie hatten Ihre Niederlassung zu Remote - Repository geschoben ( in der Regel seinen Ursprung) und dann haben Sie eine succesfull rebase (ohne Zusammenführung) durchgeführt ( git rebase --abortgibt „Nein im Gange rebase“) können Sie einfach zurückgesetzt Zweig mit dem Befehl:

git reset --hard origin / {branchName}

Beispiel:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.

nothing to commit, working directory clean
Maksym
quelle
Das ist die richtige Antwort für mich. Rebase und Commit vor Rebase hatten dieselbe Commit-ID, und wenn Sie zu HEAD {1} zurückkehren, wird Rebase einfach nicht zurückgesetzt!
Bill Kotsias
23

Verwenden refloghat bei mir nicht funktioniert.

Was für mich funktionierte, war ähnlich wie hier beschrieben . Öffnen Sie die Datei in .git / logs / refs, die nach dem Zweig benannt ist, der neu basiert wurde, und suchen Sie die Zeile, die "rebase finsihed" enthält.

5fce6b51 88552c8f Kris Leech <[email protected]> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Überprüfen Sie das zweite in der Zeile aufgeführte Commit.

git checkout 88552c8f

Nachdem ich bestätigt hatte, dass dies meine verlorenen Veränderungen enthielt, verzweigte ich mich und seufzte erleichtert auf.

git log
git checkout -b lost_changes
Kris
quelle
3
Whoa - von diesem Link: "Es gibt eine Einschränkung: Ich habe die Geschichte der Branche verloren, aber in diesem Fall war es nicht wirklich wichtig. Ich war nur froh, meine Änderungen abgerufen zu haben." ?
Ruffin
16

Denken Sie bei mehreren Commits daran, dass jedes Commit auf den gesamten Verlauf verweist, der zu diesem Commit geführt hat. Lesen Sie in Charles 'Antwort "das alte Commit" als "das neueste der alten Commits". Wenn Sie auf dieses Commit zurücksetzen, wird der gesamte Verlauf dieses Commits erneut angezeigt. Dies sollte tun, was Sie wollen.

Greg Hewgill
quelle
11

Nach der Lösung von @Allan und @Zearin wünschte ich mir, ich könnte einfach einen Kommentar abgeben, aber ich habe nicht genug Ruf, deshalb habe ich den folgenden Befehl verwendet:

Anstatt zu tun git rebase -i --abort (beachte das -i ), musste ich einfach machen git rebase --abort( ohne das -i ).

Beide unter Verwendung von -iund --abortzur gleichen Zeit verursacht Git mir eine Liste der Verwendungs / Optionen anzuzeigen.

Mein bisheriger und aktueller Zweigstellenstatus bei dieser Lösung lautet also:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$
Matheus Felipe
quelle
11

Wenn Sie erfolgreich gegen Remote Branch verzweigt haben und dies nicht git rebase --abortkönnen, können Sie dennoch einige Tricks ausführen , um Ihre Arbeit zu retten, und keine erzwungenen Pushs ausführen . Angenommen, Ihr aktueller Zweig, der versehentlich neu basiert wurde, wird aufgerufen your-branchund verfolgtorigin/your-branch

  • git branch -m your-branch-rebased # aktuellen Zweig umbenennen
  • git checkout origin/your-branch # Auschecken in den neuesten Status, dessen Ursprung bekannt ist
  • git checkout -b your-branch
  • Überprüfen git log your-branch-rebased, vergleichen git log your-branchund definieren Sie Commits, die in fehlenyour-branch
  • git cherry-pick COMMIT_HASH für jedes Commit in your-branch-rebased
  • Schieben Sie Ihre Änderungen. Bitte beachten Sie, dass zwei lokale Niederlassungen zugeordnet sind remote/your-branchund Sie nur pushen solltenyour-branch
Sergey P. aka azurblau
quelle
4

Angenommen, ich stütze den Master auf meinen Feature-Zweig zurück und erhalte 30 neue Commits, die etwas beschädigen. Ich habe festgestellt, dass es oft am einfachsten ist, nur die schlechten Commits zu entfernen.

git rebase -i HEAD~31

Interaktive Rebase für die letzten 31 Commits (es tut nicht weh, wenn Sie viel zu viele auswählen).

Nehmen Sie einfach die Commits, die Sie entfernen möchten, und markieren Sie sie mit "d" anstelle von "pick". Jetzt werden die Commits gelöscht und die Rebase effektiv rückgängig gemacht (wenn Sie nur die Commits entfernen, die Sie gerade beim Rebasis erhalten haben).

Hardev
quelle
3

Für Neulinge / alle, die Angst vor einem Hard-Reset haben, können Sie das Commit aus dem Reflog auschecken und dann als neuen Zweig speichern.

git reflog

Suchen Sie das Commit, bevor Sie mit der Neugründung beginnen. Möglicherweise müssen Sie weiter nach unten scrollen, um es zu finden (drücken Sie die Eingabetaste oder PageDown). Notieren Sie sich die HEAD-Nummer und ersetzen Sie 57:

git checkout HEAD@{57}

Überprüfen Sie den Zweig / die Commits. Wenn es gut aussieht, erstellen Sie einen neuen Zweig mit diesem HEAD:

git checkout -b new_branch_name
Andrew
quelle
2

Wenn Sie sich in einer Filiale befinden, können Sie Folgendes verwenden:

git reset --hard @{1}

Es gibt nicht nur ein Referenzprotokoll für HEAD (erhalten von git reflog), sondern auch Reflogs für jeden Zweig (erhalten von git reflog <branch>). Also, wenn Sie sind auf masterdann git reflog masterwerden alle Änderungen Liste auf diesen Zweig. Sie können zu , dass Änderungen beziehen master@{1}, master@{2}usw.

git rebase wird normalerweise HEAD mehrmals ändern, aber der aktuelle Zweig wird nur einmal aktualisiert.

@{1}ist einfach eine Verknüpfung für den aktuellen Zweig , also ist es gleich, master@{1}wenn Sie eingeschaltet sind master.

git reset --hard ORIG_HEADfunktioniert nicht, wenn Sie git resetwährend einer interaktiven verwendet rebase.

Devconsole
quelle
1

Was ich normalerweise mache ist git reset #commit_hash

bis zum letzten Commit, wo meiner Meinung nach Rebase keine Wirkung hatte.

dann git pull

Jetzt sollte Ihr Zweig genau wie Master übereinstimmen und neu basierte Commits sollten nicht darin enthalten sein.

Jetzt kann man nur noch die Commits in diesem Zweig auswählen.

mrigendra
quelle
1

Ich habe alle Vorschläge mit Reset und Reflog ohne Erfolg ausprobiert. Durch das Wiederherstellen des lokalen Verlaufs von IntelliJ wurde das Problem verlorener Dateien behoben

user3638751
quelle
Vielen Dank! Ich habe die lokale Historie noch nie zuvor verwendet, aber dies stellte sich für mich als die einfachste Möglichkeit heraus, versehentlich neu basierten Code wiederherzustellen. Sehr schönes, aber etwas verstecktes Feature.
Magnus W
0

git reset --hard origin / {branchName}

ist die richtige Lösung, um alle durch Rebase vorgenommenen lokalen Änderungen zurückzusetzen.

Damodar P.
quelle
1
Wenn Sie einen Hard-Reset durchführen, origin/branchverlieren Sie möglicherweise Änderungen zwischen HEAD und diesem Punkt. Das wollen Sie im Allgemeinen nicht.
Bluesmonk
Genau das wollte ich in meinem Fall. Also abstimmend.
Mandar Vaze
-4

Wenn Sie innerhalb einer Git-Rebase etwas durcheinander bringen, z. B. git rebase --abortwenn Sie nicht festgeschriebene Dateien haben, gehen diese verloren und git refloghelfen nicht weiter. Das ist mir passiert und Sie müssen hier über den Tellerrand hinaus denken. Wenn Sie Glück haben wie ich und IntelliJ Webstorm verwenden, können right-click->local historyund können Sie zu einem früheren Status Ihrer Datei / Ordner zurückkehren, unabhängig davon, welche Fehler Sie mit der Versionssoftware gemacht haben. Es ist immer gut, wenn eine andere Ausfallsicherheit ausgeführt wird.

stevek
quelle
5
git rebase --abortbricht eine aktive Rebase ab, macht eine Rebase nicht rückgängig . Es ist auch eine schlechte Idee, zwei VCS gleichzeitig zu verwenden. Es ist eine nette Funktion in der Jetbrains-Software, aber Sie sollten nicht beide verwenden. Es ist besser, nur Git zu lernen, insbesondere wenn Sie Fragen zu Stack Overflow beantworten, die sich mit Git befassen.
Dudewad