Eine Zusammenführung per Pull-Anfrage rückgängig machen?

158

Jemand akzeptierte eine Pull-Anfrage, die er nicht haben sollte. Jetzt haben wir eine Menge fehlerhaften Codes zusammengeführt. Wie können Sie eine Pull-Anfrage rückgängig machen? Ich wollte gerade die Änderungen am Commit kurz vor dem Zusammenführen zurücksetzen, aber ich bemerkte, dass es in einer Reihe von Commits zusammengeführt wurde. Jetzt gibt es all diese Commits von dieser Person aus Tagen vor der Fusion. Wie machst du das rückgängig?

Wille
quelle
7
Trotz des Ratschlags der akzeptierten Antwort sollten Sie BITTE nicht zwangsweise in ein Repository pushen, wenn das Repo mit anderen geteilt wird. Sie laufen Gefahr, die von anderen geleistete Arbeit zu ruinieren, und GitHub zeigt diese Pull-Anforderung möglicherweise weiterhin als zusammengeführt an. Eine andere Antwort auf diese Frage erklärt einen sichereren Weg, eine Pull-Anfrage rückgängig zu machen.
Alxndr
2
Hinweis: Zumindest jetzt (Juni 2014) schlägt GitHub die Schaltfläche "Zurücksetzen" in der Web-GUI von Pull Request vor. Siehe meine Antwort unten
VonC
1
Das Problem mit der Schaltfläche "Zurücksetzen" besteht darin, dass ein neues Commit als Umkehrung der Pull-Anforderung erstellt wird. Wenn Sie diese Änderungen schließlich zusammenführen möchten, kann die Verwendung der Schaltfläche "Zurücksetzen" dies erheblich erschweren.
FluffySamurai

Antworten:

158

Es gibt eine bessere Antwort auf dieses Problem, obwohl ich dies nur Schritt für Schritt aufschlüsseln könnte.

Sie müssen die neuesten Upstream-Änderungen wie folgt abrufen und auschecken, z. B.:

git fetch upstream
git checkout upstream/master -b revert/john/foo_and_bar

Wenn Sie sich das Festschreibungsprotokoll ansehen, sollten Sie etwas Ähnliches finden:

commit b76a5f1f5d3b323679e466a1a1d5f93c8828b269
Merge: 9271e6e a507888
Author: Tim Tom <[email protected]>
Date:   Mon Apr 29 06:12:38 2013 -0700

    Merge pull request #123 from john/foo_and_bar

    Add foo and bar

commit a507888e9fcc9e08b658c0b25414d1aeb1eef45e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 12:13:29 2013 +0000

    Add bar

commit 470ee0f407198057d5cb1d6427bb8371eab6157e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 10:29:10 2013 +0000

    Add foo

Jetzt möchten Sie die gesamte Pull-Anforderung mit der Möglichkeit zurücksetzen, sie später wieder rückgängig zu machen. Dazu müssen Sie die ID des Zusammenführungs-Commits verwenden .

Im obigen Beispiel ist das Zusammenführungs-Commit das oberste, in dem "Zusammengeführte Pull-Anforderung Nr. 123 ..." steht .

Wenn Sie dies tun, um die beiden Änderungen zurückzusetzen ( "Balken hinzufügen " und "foo hinzufügen" ), erhalten Sie in einem Commit die gesamte Pull-Anforderung, die Sie später rückgängig machen können, und halten den Änderungsverlauf sauber:

git revert -m 1 b76a5f1f5d3b323679e466a1a1d5f93c8828b269
Fehlerentwickler
quelle
6
Dies sollte die richtige Antwort sein. Es gibt einen Verweis in der git-revert-Manpage auf weitere Details aus der git-Mailingliste hier kernel.org/pub/software/scm/git/docs/howto/…
Justin Hamade
2
Warum das git checkout upstream/master -b revert/john/foo_and_bar? was macht es genau
Magne
4
@Magne - Sie erstellen einen neuen Zweig für das Zurücksetzen, in dem Sie auswählen können, wo die Umkehrung zusammengeführt werden soll. Im Grunde gibt Ihnen nur mehr Kontrolle darüber, was mit dem Zweig zu tun ist. In meinem Fall habe ich eine neue Pull-Anfrage von diesem "festen" Zweig, der die Umkehrung enthält, an unseren Entwicklungszweig gesendet, was bedeutet, dass meine neue Pull-Anfrage bei Bedarf auch zurückgesetzt werden kann. Dies geschah für eine Veröffentlichung, in der wir beschlossen, den ersten Entwurf eines neu geplanten Features herauszuholen. Kein schlechter Code, nur nicht in dieser Version.
Daniel Nalbach
3
Ich habe eine harte Lektion gelernt. Wir haben eine Funktion in unseren Entwicklungszweig verschoben, aber festgestellt, dass es Datenprobleme gibt, und sind direkt bei der Entwicklung zurückgekehrt. Später, als die Probleme behoben waren, wollten wir diesem Zweig neuere Entwicklungsfunktionen hinzufügen, um ihre Kompatibilität mit dieser Funktion zu testen, bevor wir sie pushen. Deshalb habe ich die Entwicklung wieder in den Funktionszweig integriert. Dies wendete auch das Reversion-Commit an, mit dem jede am Feature-Zweig vorgenommene Änderung aufgehoben wurde. > <
Greg
86

Sehen Sie sich Ihr Commit-Diagramm an (mit gitk oder einem ähnlichen Programm). Sie sehen Commits aus der Pull-Anforderung, und Sie sehen Ihre eigenen Commits und ein Merge-Commit (wenn es sich nicht um eine Schnellvorlauf-Merge handelt). Sie müssen nur die letzten Ihrer eigenen Commits vor dem Zusammenführen finden und den Zweig auf dieses Commit zurücksetzen.

(Wenn Sie das Reflog des Zweigs haben, sollte es noch einfacher sein, das Commit vor dem Zusammenführen zu finden.)


(Nach weiteren Informationen in den Kommentaren bearbeiten :)

Okay, schauen wir uns die Grafik an:

Screenshot 1

Ich gehe davon aus, dass das letzte (ganz rechts) Commit Ihre falsche Zusammenführung durch Pull-Anforderung war , bei der die hier gezeigte blaue Linie zusammengeführt wurde. Ihr letztes gutes Commit wäre das vorhergehende auf der schwarzen Linie, hier rot markiert:

Geben Sie hier die Bildbeschreibung ein

Auf dieses Commit zurücksetzen, und es sollte Ihnen gut gehen.

Dies bedeutet, dass Sie dies in Ihrer lokalen Arbeitskopie tun müssen (nachdem Sie sichergestellt haben, dass Sie keine nicht festgeschriebenen Inhalte mehr haben, z. B. von git stash):

git checkout master
git reset --hard 7a62674ba3df0853c63539175197a16122a739ef
gitk 

Bestätigen Sie jetzt, dass Sie sich wirklich auf dem Commit befinden, das ich dort markiert habe, und Sie werden keines der gezogenen Dinge in seiner Herkunft sehen.

git push -f origin master

(Wenn Ihre Github-Fernbedienung benannt ist origin, ändern Sie den Namen.)

Jetzt sollte auch auf Github alles richtig aussehen. Die Commits befinden sich weiterhin in Ihrem Repository, sind jedoch für keine Zweigstelle erreichbar und sollten dort keinen Schaden anrichten. (Und sie werden natürlich immer noch im Repository von RogerPaladin sein.)

(Es gibt möglicherweise eine Github-spezifische Nur-Web-Methode, um dasselbe zu tun, aber ich bin mit Github und seinem Pull-Request-Verwaltungssystem nicht allzu vertraut.)

Beachten Sie, dass jemand, der Ihren Master möglicherweise bereits mit dem falschen Commit gezogen hat, das gleiche Problem hat wie Sie derzeit und nicht wirklich einen Beitrag leisten kann. vor dem Zurücksetzen auf Ihre neue Master-Version.

Wenn dies wahrscheinlich passiert ist oder Sie einfach nur Probleme vermeiden möchten, verwenden Sie git revertstattdessen den Befehl git reset, um die Änderungen mit einem neuen Commit zurückzusetzen, anstatt auf ein älteres zurückzusetzen. (Einige Leute denken, Sie sollten niemals mit veröffentlichten Zweigen zurücksetzen.) Weitere Antworten auf diese Frage finden Sie hier.

Für die Zukunft:

Wenn Sie nur einige der Commits von RogerPaladins Zweig möchten, sollten Sie cherry-pickstattdessen anstelle von verwenden merge. Oder kommunizieren Sie mit RogerPaladin, um sie in einen separaten Zweig zu verschieben und eine neue Pull-Anfrage zu senden.

Paŭlo Ebermann
quelle
Aber wir haben eine Menge Commits zwischen dem Zusammenschluss und seinem ersten Commit. So wie wir das Merge-Commit haben, unsere eigenen Commits und dann ein weiteres Commit von ihm. Es scheint, als ob es in wirklich alten Verpflichtungen von ihm verschmolzen ist.
Will
Ja, es wird in alles zusammengeführt, was ein Vorfahr des zusammengeführten Commits ist (und nicht bereits ein Vorfahr Ihres Commits). Dies sollte Sie nicht am Zurücksetzen hindern - die Commits werden nicht von selbst neu angeordnet, wenn Sie danach keine Rebase durchgeführt haben.
Paŭlo Ebermann
1
Ja, jetzt sieht es richtig aus (abgesehen von der seltsamen Verschmelzung in sich selbst - aber dies könnte ein Fehler in der Netzwerkgraph-Software sein). :-) Es freut mich, dass ich helfen konnte.
Paŭlo Ebermann
6
Ich denke, das ist vielleicht problematisch, wenn jemand die schlechten Commits gezogen hat und später eine Pull-Anfrage sendet, die die gleichen schlechten Commits enthält, also schleichen sie sich doch in das Repo. Wäre es nicht sicherer, ein neues Commit zu erstellen, das die schlechten Commits umkehrt? Auf diese Weise werden die fehlerhaften Commits, wenn sie zu anderen Zweigen / Gabeln gezogen wurden, durch einen weiteren Zug zu diesem anderen Zweig / dieser anderen Gabel effektiv entfernt? Ich sage dies nicht als Tatsache, das ist es, was ich für wahr halte , in der gleichen Position wie das OP zu sein und ungefähr eine Stunde damit verbracht zu haben, über meine Optionen nachzudenken .
Myles McDonnell
4
@ Will ich vorschlagen, diese Antwort nicht zu akzeptieren. Dies ist in Ordnung für Code, der noch nicht gepusht wurde (in diesem Fall ist dies eine relevantere SO-Frage, aber für Code, der öffentlich freigegeben wird, indem ein git-Befehl ausgeführt wird, der den Verlauf neu schreibt (in diesem Fall reset --hardund ein Force-Push) sehr schlechte Praxis). Die Antwort von @errordeveloper unten zeigt einen Weg, dies zu tun, ohne dass die Geschichte neu geschrieben oder
erzwungen wird
34

Wenn der Zug das letzte war, was er dann tat

git reset --hard HEAD~1
samthebest
quelle
3
Befolgen Sie diese Anweisung vorsichtig, sie hat mich tatsächlich um zwei Schritte zurückgesetzt, nicht um einen.
szeitlin
1
@szeitlin Wie konnte es passieren, dass du 2 Schritte zurückgebracht hast, nicht einen? Ich weiß, dass dieser Kommentar vor mehr als 4 Jahren hinterlassen wurde, aber ich bin gespannt, ob jemand eine Antwort weiß, wie es passieren könnte. Das ist sehr wichtig für mich. Vielen Dank.
Haradzieniec
Ich erinnere mich jetzt nicht, aber ich vermute, es könnte passieren, wenn ich beim Zurücksetzen einen neuen Commit durchgeführt hätte? Ich würde es einfach mit einem Dummy-Repo testen, wenn Sie sich darüber Sorgen machen.
szeitlin
Dieser hat gut für mich funktioniert. Die kürzlich zusammengeführte Pull-Anforderung wurde gelöscht. Danach habe git reset --hard HEAD~1ich git push origin -fdas Remote-Repository aktualisiert. Aber seien Sie vorsichtig, seien Sie vorsichtig, bevor Sie dies tun.
Denis Oluka
24

Ab dem 24. Juni 2014 können Sie versuchen, eine PR einfach abzubrechen (siehe " Zurücksetzen einer Pull-Anfrage ") mit:

Einführung in die Schaltfläche "Zurücksetzen"

Sie können eine Pull-Anfrage auf GitHub einfach zurücksetzen, indem Sie auf Zurücksetzen klicken:

https://camo.githubusercontent.com/0d3350caf2bb1cba53123ffeafc00ca702b1b164/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6c696e6b2e706e67

Sie werden aufgefordert, eine neue Pull-Anforderung mit den zurückgesetzten Änderungen zu erstellen:

https://camo.githubusercontent.com/973efae3cc2764fc1353885a6a45b9a518d9b78b/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6e65772d70722e706e67

Es bleibt jedoch zu prüfen, ob diese -mRücknahme verwendet wird oder nicht (auch zum Zurücksetzen von Zusammenführungen).

Aber Adil H Raza fügt in den Kommentaren (Dezember 2019) hinzu:

Dies ist das erwartete Verhalten. Es wurde ein neuer Zweig erstellt, und Sie können einen PR von diesem neuen Zweig zu Ihrem erstellen master.
Auf diese Weise können Sie in Zukunft die Wiederherstellung bei Bedarf rückgängig machen. Dies ist die sicherste Option und ändert Ihre nicht direkt master.


Warnung : Korayem weist in den Kommentaren darauf hin, dass:

Angenommen, Sie haben nach einem Zurücksetzen einige weitere Änderungen am Git-Zweig vorgenommen und einen neuen PR aus demselben Quell- / Zielzweig erstellt.
Sie werden feststellen, dass die PR nur neue Änderungen anzeigt, aber nichts von dem, was vor dem Zurücksetzen vorhanden war .

Korayem verweist uns auf " Github: Änderungen, die nach revert ( git cherry-pick, git rebase) ignoriert werden " für mehr.

VonC
quelle
Ich habe es versucht und es wurde ein neuer Zweig erstellt, anstatt PR auf Master rückgängig zu machen.
15розный
Seltsam. Könnten Sie eine neue Frage stellen, um dieses Verhalten zu veranschaulichen?
VonC
Dies ist das erwartete Verhalten. Es wurde ein neuer Zweig erstellt, und Sie können einen PR von diesem neuen Zweig zu Ihrem Master erstellen. Auf diese Weise können Sie in Zukunft die Wiederherstellung bei Bedarf rückgängig machen. Dies ist die sicherste Option und ändert Ihren Master nicht direkt.
Adil H. Raza
1
@ AdilH.Raza Danke. Ich habe Ihren Kommentar zur besseren Sichtbarkeit in die Antwort aufgenommen.
VonC
1
@VonC Daumen drücken, um Entwickler auf der ganzen Welt vor zu viel Qual und Zeitverschwendung zu
bewahren
8

Um eine Github-Pull-Anforderung mit Commits rückgängig zu machen, die Sie nicht löschen möchten, müssen Sie Folgendes ausführen:

git reset --hard --merge <commit hash>

Der Commit-Hash ist der Commit VOR dem Zusammenführen der Pull-Anforderung. Dadurch werden alle Commits aus der Pull-Anforderung entfernt, ohne dass Commits im Verlauf beeinflusst werden.

Ein guter Weg, dies zu finden, besteht darin, zur jetzt geschlossenen Pull-Anfrage zu gehen und dieses Feld zu finden:

Anforderungsbild ziehen Anforderungsbild ziehen

Nachdem Sie das ausgeführt haben git reset, führen Sie Folgendes aus :

git push origin --force <branch name>

Dies sollte die Verzweigung vor der Pull-Anforderung zurücksetzen, OHNE dass sich Commits in der Verzweigung auf den Commit-Verlauf zwischen Commits aus der Pull-Anforderung auswirken.

BEARBEITEN:

Wenn Sie in der Pull-Anforderung auf die Schaltfläche "Zurücksetzen" klicken, wird ein zusätzliches Commit für den Zweig erstellt. Es wird NICHT aufgehoben oder getrennt. Dies bedeutet, dass Sie keine neue Pull-Anforderung öffnen können, um den gesamten Code erneut hinzuzufügen, wenn Sie auf die Schaltfläche "Zurücksetzen" klicken.

FluffySamurai
quelle
Eine großartige Möglichkeit, die Dinge zu klären, ohne dass ein verrücktes Zurücksetzen oder Kirschenpflücken erforderlich ist
Cumulo Nimbus,
Vielen Dank! Das war es, was ich vorhatte, aber das wären ungefähr 200 Commits gewesen, um Kirschen auszusuchen.
FluffySamurai
1

Ich benutze diesen Ort die ganze Zeit, danke.

Ich suchte nach einer Möglichkeit, eine Pull-Anfrage rückgängig zu machen, und kam hierher.

Ich war gerade dabei git reset --hard, "vor langer Zeit" einen schnellen Vorlauf zurück zu machen, wo ich war, bevor ich die Pull-Anfrage machte.

Neben dem Blick hierher fragte ich meinen Kollegen auch, was er tun würde, und er hatte eine typisch gute Antwort: Verwenden Sie die Beispielausgabe in der ersten Antwort oben:

git reset --hard 9271e6e

Wie bei den meisten Dingen in Git machen Sie es wahrscheinlich falsch, wenn Sie es auf eine Weise tun, die nicht einfach ist.

Mike Marshall
quelle