Wie kann ein Merge-Commit zurückgesetzt werden, das bereits an den Remote-Zweig gesendet wurde?


961

git revert <commit_hash>allein wird nicht funktionieren. -mmuss angegeben werden, und ich bin ziemlich verwirrt darüber.

Hat das schon mal jemand erlebt?




Der Link hier ist das beste Beispiel, das das Zurücksetzen des zusammengeführten Commits veranschaulicht: christianengvall.se/undo-pushed-merge-git
SK Venkat

Dies ist ein Beispiel dafür, dass das Design von gitnicht dem git-flowvon allen verwendeten -ish-Workflow entspricht. Wenn Sie developausgecheckt haben, möchten Sie natürlich den 2-Commit-Feature-Zweig zurücksetzen, der einen Fehler verursacht hat, und nicht den jahrelangen Shared Dev-Zweig. Fühlt sich lächerlich an, wenn man es auswählen muss -m 1.
Pkamb

2
Nur ein weiterer Vorschlag, der mir noch nie in den Sinn gekommen ist: Wenn eine der Commits der Filialen klein ist, fühlen Sie sich möglicherweise wohler, wenn Sie einzelne Commits anstelle eines gesamten Commits zurücksetzen.
Sridhar Sarnobat

Antworten:


1153

Die -mOption gibt die übergeordnete Nummer an . Dies liegt daran, dass ein Zusammenführungs-Commit mehr als ein übergeordnetes Element hat und Git nicht automatisch weiß, welches übergeordnete Element die Hauptzeile war und welches übergeordnete Element der Zweig war, den Sie zusammenführen möchten.

Wenn Sie ein Zusammenführungs-Commit in der Ausgabe von anzeigen, werden die übergeordneten Elemente in git logder Zeile angezeigt, die mit Folgendem beginnt Merge:

commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: 8989ee0 7c6b236
Author: Ben James <ben@example.com>
Date:   Wed Aug 17 22:49:41 2011 +0100

Merge branch 'gh-pages'

Conflicts:
    README

In dieser Situation git revert 8f937c6 -m 1erhalten Sie den Baum so, wie er war 8989ee0, und stellen git revert -m 2den Baum wieder so her, wie er war 7c6b236.

Um die übergeordneten IDs besser zu verstehen, können Sie Folgendes ausführen:

git log 8989ee0 

und

git log 7c6b236

127
aus zwei Zahlen 8989ee0, 7c6b236, die man zu gehen. Wie würde ich verstehen?
Arup Rakshit

12
Ich glaube nicht, dass man nach dem Zurücksetzen den Code im Quellzweig einfach korrigieren und wieder zusammenführen kann. kernel.org/pub/software/scm/git/docs/howto/…
IsmailS

10
Während ich nach einer besseren Erklärung suchte, fand ich diesen Artikel, von dem ich dachte, dass er die Details hervorragend durchgesehen hat. Nachdem ich gelesen hatte, stellte ich fest, dass ich wirklich nach dem RESET-Befehl suchte, gefolgt von einem Force-Push. Vielleicht hilft es jemand anderem. atlassian.com/git/tutorials/…
Funktr0n

46
@ArupRakshit Wenn Sie ausführen git log 8989ee0und git log 7c6b236, sollten Sie die Antwort wissen.
BMW

4
Git-Protokoll - Zusammengeführt, um alle Zusammenführungen anzuzeigen, und Git-Protokoll - Keine Zusammenführungen, um den Verlauf ohne Zusammenführungen anzuzeigen. Das Zusammenführen eines Zweigs bringt den zusammengeführten Zweigverlauf ins Ziel und macht es schwierig, ihn mit einem einfachen Git-Protokoll zu erkennen
Alex Punnen

370

Hier ist ein vollständiges Beispiel in der Hoffnung, dass es jemandem hilft:

git revert -m 1 <commit-hash> 
git push -u origin master

Wo <commit-hash>sich der Commit-Hash der Zusammenführung befindet, die Sie zurücksetzen möchten, und wie in der Erläuterung dieser Antwort-m 1 angegeben , gibt an, dass Sie vor der Zusammenführung zum Baum des ersten übergeordneten Elements zurückkehren möchten.

Die git revert ...Zeile schreibt Ihre Änderungen im Wesentlichen fest, während die zweite Zeile Ihre Änderungen öffentlich macht, indem sie an den Remote-Zweig gesendet werden.


21
Ich habe geglaubt, dass der git revertBefehl das erstellte Commit-Objekt bereits festgeschrieben hat. Damit dies nicht passiert, müssten Sie die --no-commitFlagge
eingeben

2
Wie bei @Delfic erwähnt, wird das Commit bereits von der ersten Zeile verwaltet (ich brauchte ein: wq, um es zu validieren), sodass die zweite Zeile nicht erforderlich ist.
eka808

1
das ist verwirrend. Es gibt nur 2 Zeilen und kein Git Commit. Kann jemand bitte bearbeiten.
Jay Random

176

Ben hat Ihnen gesagt, wie Sie ein Merge-Commit rückgängig machen können, aber es ist sehr wichtig , dass Sie dies erkennen

"... erklärt, dass Sie niemals die durch die Zusammenführung eingebrachten Baumänderungen wünschen. Infolgedessen führen spätere Zusammenführungen nur zu Baumänderungen, die durch Commits eingeführt wurden, die keine Vorfahren der zuvor rückgängig gemachten Zusammenführung sind. Dies kann sein oder auch nicht was du willst. " (git-merge manpage) .

In einer Artikel- / Mailinglistennachricht, die über die Manpage verlinkt ist, werden die beteiligten Mechanismen und Überlegungen aufgeführt. Stellen Sie nur sicher, dass Sie verstehen, dass Sie den Zweig nicht einfach später wieder zusammenführen können, wenn Sie das Zusammenführungs-Commit zurücksetzen, und erwarten, dass dieselben Änderungen wieder auftreten.


81
Sie können die Wiederherstellung jedoch zurücksetzen, um sie bei Bedarf zurückzubekommen.
Bangalore

5
Vielen Dank. Sehr nützlich zu wissen, da der Anwendungsfall zum Rückgängigmachen einer Zusammenführung - beispielsweise aufgrund eines Fehlers - und zum erneuten Zusammenführen des gesamten Zweigs, sobald der Fehler behoben ist, häufig vorkommt.
Komponente 10

3
Wenn Sie wie ich sind und später die Zusammenführung wollten, können Sie entweder die Wiederherstellung rückgängig machen oder die Änderung auswählen, die Sie zurückgesetzt haben.
UnitasBrooks

In meiner Situation musste ich das Zurücksetzen rückgängig machen, um mein Problem mit dem Zurücksetzen von Änderungen zu erhalten. Kirschernte könnte ein ordentlicher Weg sein? Ich werde das nächste Mal versuchen ...
Steven Anderson

79

Sie können diese Schritte ausführen, um die falschen Festschreibungen zurückzusetzen oder Ihren Remote-Zweig auf den korrekten HEAD / Status zurückzusetzen.

  1. Checken Sie den Remote-Zweig zum lokalen Repo aus.
    git checkout development
  2. Kopieren Sie den Commit-Hash (dh die ID des Commits unmittelbar vor dem falschen Commit) aus dem Git-Protokoll git log -n5

    Ausgabe:

    Festschreiben 7cd42475d6f95f5896b6f02e902efab0b70e8038 "Zweig 'Falsch-Festschreiben' in 'Entwicklung' zusammenführen"
    Festschreiben f9a734f8f44b0b37ccea769b9a2fd774c0f0c012 "Dies ist ein falsches
    Festschreiben" Festschreiben 3779ab50e72908d9

  3. Setzen Sie den Zweig auf den im vorherigen Schritt kopierten Commit-Hash zurück
    git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)

  4. Führen Sie die git status , um alle Änderungen anzuzeigen, die Teil des falschen Commits waren.
  5. einfach laufen git reset --hard , um alle diese Änderungen rückgängig zu machen.
  6. Drücken Sie Ihren lokalen Zweig zwangsweise auf Remote und stellen Sie fest, dass Ihr Commit-Verlauf sauber ist, wie er war, bevor er verschmutzt wurde.
    git push -f origin development

4
Was ist, wenn in der Zwischenzeit 20 Entwickler die neueste Entwicklerzusammenführung durchgeführt haben?
Ewoks

2
Ich würde nicht zwingen, einen Entwicklungszweig zu pushen, wenn 20 Entwickler im Team diesen Zweig verwenden. :) In diesem Fall ist es ratsam, nur ein Revert-Commit durchzuführen.
Ssasi

4
Dies ist eine sehr gute Lösung, wenn Sie alleine arbeiten oder sicher sind, dass keine anderen Entwickler die Commits gezogen haben, die Sie vermasselt haben
Kyle B


30

Um das Protokoll sauber zu halten, da nichts passiert ist (mit einigen Nachteilen bei diesem Ansatz (aufgrund von push -f)):

git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>

'Commit-Hash-vor-Zusammenführen' stammt aus dem Protokoll (Git-Protokoll) nach dem Zusammenführen.


Hinweis: Wenn Sie dies in Ihrem Unternehmen tun, haben Sie möglicherweise keine Erlaubnis.
Eneski

3
Machen Sie niemals push -fein gemeinsames Repo
Baptiste Mille-Mathias

17

Manchmal ist der effektivste Weg zum Rollback das Zurücktreten und Ersetzen.

git log

Verwenden Sie den 2. Commit-Hash (vollständiger Hash, auf den Sie vor dem aufgeführten Fehler zurückgreifen möchten) und verzweigen Sie ihn dann von dort aus neu.

git checkout -b newbranch <HASH>

Löschen Sie dann den alten Zweig, kopieren Sie den neuen Zweig an seiner Stelle und starten Sie von dort aus neu.

git branch -D oldbranch
git checkout -b oldbranch newbranch

Wenn es gesendet wurde, löschen Sie den alten Zweig aus allen Repositorys, verschieben Sie den erneuerten Zweig in die zentralste Position und ziehen Sie ihn wieder auf alle herunter.


4
Die Warnung vor der Sendung sollte wirklich deutlicher sein, wie schrecklich diese Idee ist. Dies beschädigt alle Versionen dieses Zweigs und ist nur dann wirklich nützlich, wenn Sie mit einem Remote-Repository (Github / Bitbucket) arbeiten, auf das nur Sie Zugriff haben.
RobbyD

Nicht so schlimm wie das Herunterschalten geänderter Konfigurationsdateien in die Produktion. Es wird nicht beschädigt, es ist nur eine Umzweigung eines früheren Commits, also ist es eine Rundum-Möglichkeit, den Verzweigungszeiger auf eine frühere Version zu verschieben. Hoffentlich wirkt es sich nur auf das lokale Repository aus
ppostma1

5

Wenn Sie ein mergeCommit zurücksetzen möchten, müssen Sie Folgendes tun.

  1. Überprüfen git logSie zunächst die ID Ihres Merge-Commits. Sie finden auch mehrere übergeordnete IDs, die mit der Zusammenführung verknüpft sind (siehe Abbildung unten).

Geben Sie hier die Bildbeschreibung ein

Notieren Sie sich die gelb dargestellte Merge-Commit-ID. Die übergeordneten IDs sind diejenigen, die in der nächsten Zeile als geschrieben werden Merge: parent1 parent2. Jetzt...

Kurzgeschichte:

  1. Wechseln Sie zu dem Zweig, in dem die Zusammenführung durchgeführt wurde. Dann machen Sie einfach das, git revert <merge commit id> -m 1was eine viKonsole zum Eingeben einer Commit-Nachricht öffnet . Schreiben, speichern, beenden, fertig!

Lange Geschichte:

  1. Wechseln Sie zu dem Zweig, in dem die Zusammenführung durchgeführt wurde. In meinem Fall ist es der testZweig und ich versuche, den feature/analytics-v3Zweig daraus zu entfernen .

  2. git revertist der Befehl, der ein Commit zurücksetzt. Aber es gibt einen bösen Trick, wenn ein mergeCommit zurückgesetzt wird. Sie müssen das -mFlag eingeben, sonst schlägt es fehl. Von hier an müssen Sie entscheiden, ob Sie Ihren Zweig zurücksetzen und ihn so aussehen lassen möchten, als wäre er genau auf parent1oder parent2über:

git revert <merge commit id> -m 1(kehrt zurück zu parent2)

git revert <merge commit id> -m 2(kehrt zurück zu parent1)

Sie können diese Eltern protokollieren, um herauszufinden, welchen Weg Sie einschlagen möchten, und das ist die Wurzel aller Verwirrung.


5

Alle Antworten deckten bereits die meisten Dinge ab, aber ich werde meine 5 Cent hinzufügen. Kurz gesagt, das Zurücksetzen eines Merge-Commits ist ganz einfach:

git revert -m 1 <commit-hash>

Wenn Sie die Berechtigung haben, können Sie sie direkt in den "Master" -Zweig verschieben. Andernfalls verschieben Sie sie einfach in Ihren "Zurücksetzen" -Zweig und erstellen eine Pull-Anforderung.

Weitere nützliche Informationen zu diesem Thema finden Sie hier: https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html


1

Ich fand, dass das Erstellen eines umgekehrten Patches zwischen zwei bekannten Endpunkten und das Anwenden dieses Patches funktionieren würde. Dies setzt voraus, dass Sie Snapshots (Tags) aus Ihrem Hauptzweig oder sogar eine Sicherung Ihres Hauptzweigs erstellt haben, z. B. master_bk_01012017.

Angenommen, der Codezweig, den Sie in master zusammengeführt haben, war mycodebranch.

  1. Kasse Master.
  2. Erstellen Sie einen vollständigen binären Reverse Patch zwischen dem Master und Ihrem Backup. git diff --binary master..master_bk_01012017 > ~/myrevert.patch
  3. Überprüfen Sie Ihren Patch git apply --check myrevert.patch
  4. Patch mit Abmeldung anwenden git am --signoff < myrevert.patch
  5. Wenn Sie diesen Code nach dem Fixieren erneut eingeben müssen, müssen Sie den zurückgesetzten Master abzweigen und die Fixverzweigung auschecken git branch mycodebranch_fix git checkout mycodebranch_fix
  6. Hier müssen Sie den SHA-Schlüssel für das Zurücksetzen finden und das Zurücksetzen zurücksetzen git revert [SHA]
  7. Jetzt können Sie mit mycodebranch_fix die Probleme beheben, festschreiben und nach Abschluss erneut in den Master einbinden.

1

Die richtig markierte Antwort hat bei mir funktioniert, aber ich musste einige Zeit aufwenden, um festzustellen, was los ist. Deshalb habe ich beschlossen, eine Antwort mit einfachen, einfachen Schritten für Fälle wie meinen hinzuzufügen.

Nehmen wir an, wir haben die Zweige A und B. Sie haben Zweig A in Zweig B zusammengeführt und Zweig B auf sich selbst verschoben, sodass die Zusammenführung jetzt Teil davon ist. Sie möchten jedoch zum letzten Commit vor dem Zusammenführen zurückkehren. Was tun? Sie machen?

  1. Gehen Sie zu Ihrem Git-Stammordner (normalerweise dem Projektordner) und verwenden Sie git log
  2. Sie sehen den Verlauf der letzten Commits - die Commits haben Commit / Author / Date-Eigenschaften, während die Merges auch eine Merge-Eigenschaft haben - also sehen Sie sie wie folgt:

    commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>

  3. Verwenden Sie git log <parentHashA>und git log <parentHashB>- Sie sehen die Commit-Historien dieser übergeordneten Zweige - die ersten Commits in der Liste sind die neuesten

  4. Nehmen <commitHash>Sie das gewünschte Commit, gehen Sie zu Ihrem Git-Stammordner und verwenden Sie es. Dadurch git checkout -b <newBranchName> <commitHash>wird ein neuer Zweig erstellt, der mit dem letzten Commit beginnt, das Sie vor dem Zusammenführen ausgewählt haben. Voila, fertig!


0

Ich habe dieses Problem auch bei einer PR festgestellt, die mit dem Hauptzweig eines GitHub-Repos zusammengeführt wurde.

Da ich nur ein paar geänderte Dateien ändern , wollte aber nicht die ganzen Veränderungen die PR brachte, musste ich amenddas merge commitmit git commit --am.

Schritte:

  1. Gehen Sie zu dem Zweig, in dem Sie einige geänderte Dateien ändern / zurücksetzen möchten
  2. Nehmen Sie die gewünschten Änderungen gemäß den geänderten Dateien vor
  3. laufen git add *odergit add <file>
  4. ausführen git commit --amund validieren
  5. Lauf git push -f

Warum es interessant ist:

  • Das Commit des PR-Autors bleibt unverändert
  • Es bricht nicht den Git-Baum
  • Sie werden als Committer markiert (der Autor des Merge-Commits bleibt unverändert).
  • Git verhält sich so, als hätten Sie Konflikte gelöst. Es entfernt / ändert den Code in geänderten Dateien, als ob Sie GitHub manuell anweisen, ihn nicht so wie er ist zusammenzuführen

0

Ich habe über diesen Link eine gute Erklärung für das Zurücksetzen der Zusammenführung gefunden und die unten stehende Erklärung kopiert. Dies ist hilfreich, falls der folgende Link nicht funktioniert.

So setzen Sie eine fehlerhafte Zusammenführung zurück rückgängig macht Alan (alan@clueserver.org) sagte:

Ich habe eine Hauptniederlassung. Wir haben einen Zweig davon, an dem einige Entwickler arbeiten. Sie behaupten, es sei fertig. Wir führen es in der Hauptniederlassung zusammen. Es bricht etwas, also kehren wir die Zusammenführung zurück. Sie nehmen Änderungen am Code vor. Sie bringen es zu einem Punkt, an dem sie sagen, dass es in Ordnung ist und wir wieder zusammenführen. Bei der Prüfung stellen wir fest, dass sich Codeänderungen, die vor dem Zurücksetzen vorgenommen wurden, nicht im Hauptzweig befinden, sondern Codeänderungen nach dem Zurücksetzen im Hauptzweig. und bat um Hilfe, um sich von dieser Situation zu erholen.

Die Geschichte unmittelbar nach der "Rückkehr der Fusion" würde folgendermaßen aussehen:

---o---o---o---M---x---x---W
              /
      ---A---B

Wenn sich A und B auf der Seitenentwicklung befinden, die nicht so gut war, ist M die Zusammenführung, die diese vorzeitigen Änderungen in die Hauptlinie bringt, x sind Änderungen, die nicht mit dem zusammenhängen, was der Seitenzweig auf der Hauptlinie getan und bereits vorgenommen hat, und W ist die " Zurücksetzen der Zusammenführung M "(sieht W M nicht verkehrt herum aus?). IOW, "diff W ^ .. W" ist ähnlich wie "diff -RM ^ .. M".

Ein solches "Zurücksetzen" einer Zusammenführung kann erfolgen mit:

$ git revert -m 1 M Nachdem die Entwickler des Seitenzweigs ihre Fehler behoben haben, sieht der Verlauf möglicherweise folgendermaßen aus:

---o---o---o---M---x---x---W---x
              /
      ---A---B-------------------C---D

wo C und D reparieren sollen, was in A und B kaputt war, und Sie möglicherweise bereits einige andere Änderungen an der Hauptlinie nach W haben.

Wenn Sie den aktualisierten Seitenzweig zusammenführen (mit D an der Spitze), wird keine der in A oder B vorgenommenen Änderungen im Ergebnis angezeigt, da sie von W zurückgesetzt wurden. Das hat Alan gesehen.

Linus erklärt die Situation:

Das Zurücksetzen eines regulären Commits macht das, was dieses Commit bewirkt hat, effektiv rückgängig und ist ziemlich einfach. Durch das Zurücksetzen eines Zusammenführungs-Commits werden jedoch auch die Daten rückgängig gemacht, die durch das Commit geändert wurden. Die Auswirkungen auf den Verlauf werden , dass die Zusammenführung hatte. Die Zusammenführung wird also weiterhin bestehen, und es wird weiterhin als Zusammenschluss der beiden Zweige angesehen, und bei zukünftigen Zusammenführungen wird diese Zusammenführung als der letzte gemeinsame Zustand angesehen - und die Rücknahme, die die eingeführte Zusammenführung rückgängig gemacht hat, hat keinerlei Auswirkungen darauf. Ein "Zurücksetzen" macht also die Datenänderungen rückgängig, aber es ist sehr viel nicht jedoch absolut nicht rückgängig gemacht, da die Auswirkungen eines Commits auf den Repository-Verlauf nicht rückgängig gemacht werden. Wenn Sie also "Zurücksetzen" als "Rückgängig" betrachten, werden Sie diesen Teil der Rückgängigmachung immer verpassen. Ja, die Daten werden rückgängig gemacht, aber nein, der Verlauf wird nicht rückgängig gemacht. In einer solchen Situation möchten Sie zuerst die vorherige Wiederherstellung zurücksetzen, wodurch der Verlauf folgendermaßen aussehen würde:

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

wobei Y die Rückkehr von W ist. Eine solche "Rückkehr der Rückkehr" kann durchgeführt werden mit:

$ git revert W Dieser Verlauf würde (ohne Berücksichtigung möglicher Konflikte zwischen dem, was W und W..Y geändert haben) bedeuten, dass W oder Y überhaupt nicht im Verlauf enthalten sind:

---o---o---o---M---x---x-------x----
              /
      ---A---B-------------------C---D

und das erneute Zusammenführen des Seitenzweigs führt nicht zu Konflikten, die sich aus einem früheren Zurücksetzen und Zurücksetzen des Zurücksetzens ergeben.

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

Natürlich können die in C und D vorgenommenen Änderungen immer noch mit dem in Konflikt stehen, was von einem der x vorgenommen wurde, aber das ist nur ein normaler Zusammenführungskonflikt.


-2

Wie Ryan bereits erwähnt hat, git revertkönnte das Zusammenführen später schwierig werden, ist also git revertmöglicherweise nicht das, was Sie wollen. Ich fand, dass die Verwendung des git reset --hard <commit-hash-prior-to-merge>Befehls hier nützlicher ist.

Sobald Sie den Hard-Reset-Teil durchgeführt haben, können Sie das Drücken auf den Remote-Zweig erzwingen, dh git push -f <remote-name> <remote-branch-name>wo <remote-name>häufig genannt wird origin. Ab diesem Zeitpunkt können Sie erneut zusammenführen, wenn Sie möchten.


4
Alles, was Force-Pushs beinhaltet, ist eine schlechte Idee, es sei denn, Sie sind der einzige, der das Repo verwendet, und Sie wissen genau, was Sie tun. Das Zurücksetzen mit git revert und möglicherweise das Zurücksetzen mit git revert (wenn Sie die Dinge wieder zurückbringen müssen) ist eine viel sicherere Alternative.
Oyvind
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.