Wie kann ich mehrere Git-Commits rückgängig machen?

Lesezeit: 11 Minuten

Benutzer-Avatar
Rechnung

Ich habe ein Git-Repository, das so aussieht:

A <- B <- C <- D <- HEAD

Ich möchte, dass der Kopf des Zweigs auf A zeigt, dh ich möchte, dass B, C, D und HEAD verschwinden, und ich möchte, dass Kopf gleichbedeutend mit A ist.

Es hört sich so an, als könnte ich entweder versuchen, eine Rebase durchzuführen (gilt nicht, da ich Änderungen dazwischen geschoben habe) oder zurücksetzen. Aber wie kann ich mehrere Commits rückgängig machen? Setze ich einen nach dem anderen zurück? Ist die Reihenfolge wichtig?

  • Wenn Sie die Fernbedienung nur zurücksetzen möchten, können Sie sie mit allem schlagen! Aber lassen Sie uns den vierten Commit von vor verwenden: git push -f HEAD~4:master (vorausgesetzt, der Remote-Zweig ist der Master). Ja, Sie können jedes Commit so pushen.

    – u0b34a0f6ae

    23. September 2009 um 1:01 Uhr

  • Wenn Leute gezogen haben, müssen Sie einen Commit machen, der Änderungen mit rückgängig macht git revert.

    – Jakub Narębski

    23. September 2009 um 8:21 Uhr

  • Verwenden Sie git show HEAD~4, um sicherzustellen, dass Sie zur Fernbedienung auf die richtige Seite drücken

    – Mâtt Frëëman

    11. Juni 2016 um 3:08 Uhr

  • Mögliches Duplikat von How to Undo last Commit(s) in Git?

    – Jim fiel

    14. Februar 2017 um 18:53 Uhr

  • “Ist die Reihenfolge wichtig?” Ja, wenn die Commits dieselben Zeilen in denselben Dateien betreffen. Dann sollten Sie damit beginnen, den letzten Commit rückgängig zu machen, und sich zurückarbeiten.

    – Avantursen

    22. April 2017 um 11:26 Uhr

Benutzer-Avatar
Jakub Narębski

Erweitern, was ich in einem Kommentar geschrieben habe

Die allgemeine Regel ist, dass Sie den von Ihnen veröffentlichten Verlauf nicht umschreiben (ändern) sollten, weil jemand seine Arbeit darauf basieren könnte. Wenn Sie den Verlauf umschreiben (ändern), würden Sie Probleme beim Zusammenführen ihrer Änderungen und beim Aktualisieren für sie bekommen.

Die Lösung besteht also darin, eine zu erstellen neues Commitment welche macht Änderungen rückgängig die du loswerden willst. Sie können dies mit tun git zurücksetzen Befehl.

Sie haben folgende Situation:

A <-- B  <-- C <-- D                                  <-- master <-- HEAD

(Pfeile beziehen sich hier auf die Richtung des Zeigers: die „Eltern“-Referenz im Fall von Commits, die oberste Festschreibung im Fall des Zweigkopfs (Branch Ref) und der Name des Zweigs im Fall der HEAD-Referenz).

Was Sie erstellen müssen, ist Folgendes:

A <-- B  <-- C <-- D <-- [(BCD)-1]                   <-- master <-- HEAD

wo [(BCD)^-1] bedeutet das Commit, das Änderungen in den Commits B, C, D rückgängig macht. Mathematik sagt uns, dass (BCD)-1 = D-1 C-1 B-1sodass Sie die erforderliche Situation mit den folgenden Befehlen erhalten können:

$ git revert --no-commit D
$ git revert --no-commit C
$ git revert --no-commit B
$ git commit -m "the commit message for all of them"

Funktioniert für alles außer Merge-Commits.


Alternative Lösung wäre zu Kasse Inhalt von Commit A und schreiben Sie diesen Zustand fest. Funktioniert auch mit Merge-Commits. Hinzugefügte Dateien werden jedoch nicht gelöscht. Wenn Sie irgendwelche lokalen Änderungen haben git stash sie zuerst:

$ git checkout -f A -- . # checkout that revision over the top of local files
$ git commit -a

Dann hätten Sie folgende Situation:

A <-- B  <-- C <-- D <-- A'                       <-- master <-- HEAD

Der Commit A’ hat denselben Inhalt wie Commit A, ist aber ein anderer Commit (Commit-Nachricht, Eltern, Commit-Datum).


Alternative Lösung von Jeff Ferland, modifiziert von Charles Bailey, baut auf der gleichen Idee auf, verwendet aber git zurücksetzen. Hier ist es leicht modifiziert, so FUNKTIONIERT FÜR ALLES:

$ git reset --hard A
$ git reset --soft D # (or ORIG_HEAD or @{1} [previous location of HEAD]), all of which are D
$ git commit

  • Wenn Sie Dateien in B, C oder D hinzugefügt haben git checkout -f A -- . Diese werden nicht gelöscht, Sie müssen dies manuell tun. Ich habe diese Strategie jetzt angewendet, danke Jakub

    – Oma

    31. März 2011 um 14:56 Uhr

  • Diese Lösungen sind nicht gleichwertig. Der erste löscht keine neu erstellten Dateien.

    – m33lky

    26. Januar 2012 um 5:57 Uhr

  • @Jerry: git checkout foo könnte Kasse bedeuten Zweig foo (Zur Filiale wechseln) oder zur Kasse gehen Datei foo (aus dem Index). -- wird zur Disambiguierung verwendet, z git checkout -- foo geht es immer um Datei.

    – Jakub Narębski

    23. Januar 2013 um 2:34 Uhr

  • Zusätzlich zu einer großartigen Antwort. Diese Kurzform funktioniert bei mir git revert --no-commit D C B

    – gutdan97

    9. August 2013 um 12:34 Uhr

  • @welldan97: Danke für einen Kommentar. Beim Schreiben dieser Antwort git revert akzeptierte keine mehrfachen Commits; es ist ziemlich neu hinzugekommen.

    – Jakub Narębski

    9. August 2013 um 18:39 Uhr

Benutzer-Avatar
Tieftauchgang

Sauberer Weg, den ich nützlich fand

git revert --no-commit HEAD~3..
git commit -m "your message regarding reverting the multiple commits"

Dieser Befehl macht die letzten 3 Commits mit nur einem Commit rückgängig.

Schreibt den Verlauf auch nicht neu, erfordert also keinen Kraftstoß.

Das .. hilft, eine Reichweite zu schaffen. Bedeutung HEAD~3.. ist das gleiche wie HEAD~3..HEAD

  • Wie kann das funktionieren, wenn kein Commit vorhanden ist? Was muss zusätzlich zum obigen Befehl getan werden? Welche Git-Befehle werden vor/nach diesem Befehl benötigt?

    – Johannes Klein

    23. Oktober 2017 um 19:18 Uhr


  • @JohnLittle es inszeniert die Änderungen. git commit von dort aus wird das Commit tatsächlich durchgeführt.

    – x1a4

    1. November 2017 um 20:08 Uhr

  • Dies funktioniert nicht, wenn einige Commits Merge-Commits sind.

    – MegaManX

    7. September 2018 um 13:51 Uhr


  • Was machen die beiden Punkte am Ende?

    – Kardamom

    18. Dezember 2018 um 10:09 Uhr

  • @cardamom Diese geben einen Bereich an. HEAD~3.. ist das gleiche wie HEAD~3..HEAD

    – Toine H

    18. Dezember 2018 um 15:41 Uhr

Benutzer-Avatar
Sieger

Dazu müssen Sie nur die verwenden zurückkehren Befehl, der den Bereich der Commits angibt, die zurückgesetzt werden sollen.

Unter Berücksichtigung Ihres Beispiels müssten Sie Folgendes tun (vorausgesetzt, Sie befinden sich im Zweig „Master“):

git revert master~3..master

oder git revert B...D oder git revert D C B

Dadurch wird ein neuer Commit in Ihrem Lokal mit dem umgekehrten Commit von B, C und D erstellt (was bedeutet, dass durch diese Commits eingeführte Änderungen rückgängig gemacht werden):

A <- B <- C <- D <- BCD' <- HEAD

  • git revert --no-commit HEAD~2.. ist eine etwas idiomatischere Art, dies zu tun. Wenn Sie sich im Master-Zweig befinden, müssen Sie master nicht erneut angeben. Das --no-commit Option lässt git versuchen, alle Commits auf einmal rückgängig zu machen, anstatt den Verlauf mit mehreren zu verunreinigen revert commit ... Nachrichten (vorausgesetzt, das ist, was Sie wollen).

    – kubi

    15. Januar 2013 um 18:49 Uhr

  • @Victor Ich habe deinen Commit-Bereich korrigiert. Der Anfang des Sortiments ist exklusiv, dh nicht enthalten. Wenn Sie also die letzten 3 Commits zurücksetzen möchten, müssen Sie den Bereich von beginnen das Elternteil des 3. Commits, dh master~3.

    Benutzer456814

    25. April 2014 um 18:50 Uhr

  • @kubi gibt es keine Möglichkeit, die SHAs mit einem einzigen Commit in eine Commit-Nachricht aufzunehmen (Ihre Methode, aber ohne die rückgängig gemachten Commits manuell eingeben zu müssen)?

    – Chris S

    1. Oktober 2015 um 18:33 Uhr

  • @ChrisS Mein erster Gedanke wäre, nicht zu verwenden --no-commit (Sie erhalten also für jeden Revert ein separates Commit) und quetschen sie dann alle in einem interaktiven Rebase zusammen. Die kombinierte Commit-Nachricht enthält alle SHAs, und Sie können sie mit Ihrem bevorzugten Commit-Nachrichteneditor nach Belieben anordnen.

    – Radon Rosborough

    15. November 2016 um 20:52 Uhr

  • Sicher genug, wenn Sie dies ohne tun --no-commit es macht sie einzeln und Sie müssen weiter tippen git revert --continue immer und immer wieder für jeden … verdammt, ich hatte gehofft, Git hätte eine freundliche Commit-Option wie “mach sie alle und liste alle Hashes für mich in einem einzigen Commit auf”, aber es scheint nicht 😐

    – Rogerpack

    12. Oktober 2020 um 14:04 Uhr

git reset --hard a
git reset --mixed d
git commit

Das wird als Rückfall für alle auf einmal wirken. Geben Sie eine gute Commit-Nachricht.

Benutzer-Avatar
konyak

Ähnlich wie bei Jakubs Antwort können Sie auf diese Weise einfach aufeinanderfolgende Commits auswählen, die zurückgesetzt werden sollen.

# Revert all commits from and including B to HEAD, inclusively
git revert --no-commit B^..HEAD
git commit -m 'message'

  • Ihre Lösung hat für mich gut funktioniert, aber mit einer leichten Modifikation. Wenn wir diesen Fall Z -> A -> B -> C -> D -> HEAD haben und ich in den A-Zustand zurückkehren möchte, müsste ich seltsamerweise git revert –no-commit Z ausführen. KOPF

    – Bogdan

    22. Februar 2016 um 16:42 Uhr

  • Stimme @Bogdan zu, der Revert-Bereich ist so: SHA_TO_REVERT_TO..HEAD

    – Wadym Tymirov

    10. Mai 2016 um 16:44 Uhr

  • Die Reichweite ist falsch. Es sollte sein B^..HEADandernfalls wird B ausgeschlossen.

    – Tessus

    28. April 2018 um 3:50 Uhr


  • Stimme @tessus zu, also wäre das Richtige zu tun: git revert --no-commit B^..HEAD oder git revert --no-commit A..HEAD

    – Yoho

    29. September 2018 um 0:09 Uhr


Benutzer-Avatar
Peter Mortensen

Stellen Sie zunächst sicher, dass Ihre Arbeitskopie nicht verändert wurde.

Dann:

git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply

Und dann einfach zustimmen. Vergessen Sie nicht, den Grund für die Rücknahme zu dokumentieren.

  • Ihre Lösung hat für mich gut funktioniert, aber mit einer leichten Modifikation. Wenn wir diesen Fall Z -> A -> B -> C -> D -> HEAD haben und ich in den A-Zustand zurückkehren möchte, müsste ich seltsamerweise git revert –no-commit Z ausführen. KOPF

    – Bogdan

    22. Februar 2016 um 16:42 Uhr

  • Stimme @Bogdan zu, der Revert-Bereich ist so: SHA_TO_REVERT_TO..HEAD

    – Wadym Tymirov

    10. Mai 2016 um 16:44 Uhr

  • Die Reichweite ist falsch. Es sollte sein B^..HEADandernfalls wird B ausgeschlossen.

    – Tessus

    28. April 2018 um 3:50 Uhr


  • Stimme @tessus zu, also wäre das Richtige zu tun: git revert --no-commit B^..HEAD oder git revert --no-commit A..HEAD

    – Yoho

    29. September 2018 um 0:09 Uhr


Benutzer-Avatar
Peter Mortensen

Ich bin so frustriert, dass diese Frage nicht einfach beantwortet werden kann. Jede andere Frage bezieht sich darauf, wie man richtig zurückkehrt und die Geschichte bewahrt. Diese Frage sagt „Ich möchte, dass der Kopf des Zweigs auf A zeigt, dh ich möchte, dass B, C, D und HEAD darauf zeigen verschwinden und ich möchte, dass Kopf gleichbedeutend mit A ist.”

git checkout <branch_name>
git reset --hard <commit Hash for A>
git push -f

Ich habe viel gelernt, als ich Jakubs Post gelesen habe, aber ein Typ in der Firma (mit Zugriff auf unseren „Testing“-Zweig ohne Pull-Request) hat wie fünf schlechte Commits gepusht und versucht, einen Fehler zu beheben und zu beheben und zu beheben, den er fünf Commits gemacht hat vor. Nicht nur das, es wurden auch der ein oder andere Pull-Request akzeptiert, der nun schlecht war. Vergiss es; Ich habe den letzten guten Commit (abc1234) gefunden und einfach das grundlegende Skript ausgeführt:

git checkout testing
git reset --hard abc1234
git push -f

Ich habe den anderen fünf Leuten, die in diesem Repository arbeiten, gesagt, dass sie sich besser ihre Änderungen der letzten paar Stunden notieren und die letzten Tests löschen/neu verzweigen sollten. Das Ende der Geschichte.

  • Ich hatte die Commits nicht veröffentlicht, also war dies die Antwort, die ich brauchte. Danke, @Suamere.

    – Tom Baron

    30. November 2016 um 17:37 Uhr


  • Der bessere Weg, dies zu tun, ist git push --force-with-lease, der den Verlauf nur neu schreibt, wenn sich nach oder innerhalb des Bereichs der zu verdampfenden Commits niemand auf den Zweig festgelegt hat. Wenn andere Personen den Zweig verwendet haben, sollte seine Historie niemals umgeschrieben werden, und der Commit sollte einfach sichtbar zurückgesetzt werden.

    – frandroid

    1. Dezember 2017 um 16:59 Uhr


  • @frandroid “Geschichte sollte niemals umgeschrieben werden”, nur der Sith-Deal in absoluten Zahlen. Die Frage dieses Threads und der Punkt meiner Antwort ist genau, dass für ein bestimmtes Szenario der gesamte Verlauf gelöscht werden sollte.

    – Suamere

    24. April 2018 um 2:18 Uhr

  • @Suamere Sicher, das ist die Frage. Aber da Ihre Antwort erwähnt, was Sie den anderen Jungs zu sagen hatten, gibt es Potenzial für Ärger. Aus persönlicher Erfahrung kann push -f Ihre Codebasis durcheinander bringen, wenn andere Leute nach dem, was Sie zu löschen versuchen, begangen haben. –force-with-lease erzielt das gleiche Ergebnis, außer dass es Ihren Arsch rettet, wenn Sie Ihr Repo durcheinander bringen würden. Warum das Risiko eingehen? Wenn –force-with-lease fehlschlägt, können Sie sehen, welches Commit im Weg steht, richtig bewerten, anpassen und es erneut versuchen.

    – frandroid

    28. April 2018 um 15:02 Uhr

  • @Suamere Danke! Ich stimme zu, dass die Frage eindeutig besagt, dass sie die Geschichte neu schreiben möchte. Ich bin in der gleichen Situation wie Sie und ich vermute das OP, da jemand versehentlich Dutzende von hässlichen Reverts und seltsamen Commits und Reverts von Reverts gemacht hat (während ich im Urlaub war) und der Zustand zurückgesetzt werden muss. In jedem Fall sollte dies zusammen mit einer guten gesunden Warnung die akzeptierte Antwort sein.

    – Lee Richardson

    19. Juni 2019 um 13:53 Uhr

1013840cookie-checkWie kann ich mehrere Git-Commits rückgängig machen?

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

Privacy policy