Zurücksetzen einer Rückwärtszusammenführung auf Mercurial


77

Wie kann man den Effekt einer Verschmelzung auf polarisierte Zweige umkehren, ohne an Qualen zu sterben?

Dieses Problem plagt mich seit Monaten und ich habe endlich aufgegeben.

Sie haben 1 Repository mit 2 benannten Zweigen. A und B.

Änderungen an A treten zwangsläufig bei B auf.

Änderungen, die direkt auf B auftreten, dürfen NIEMALS auf A erfolgen.

In einer solchen Konfiguration führt das Zusammenführen von "B" mit "A" zu einem schwerwiegenden Problem im Repository, da alle Änderungen an B in A so angezeigt werden, als wären sie in A vorgenommen worden.

Der einzige "normale" Weg, um sich von dieser Situation zu erholen, scheint darin zu bestehen, die Zusammenführung "zurückzuziehen", dh:

 hg up -r A 
 hg backout -r BadMergeRev --parent BadMergerevBeforeOnA 

Das sieht alles gut und gut aus, bis Sie sich entscheiden, später in die richtige Richtung zu verschmelzen, und am Ende alle möglichen bösen Dinge passieren und Code, der in einem bestimmten Zweig B gelöscht / auskommentiert wurde, plötzlich nicht mehr gelöscht oder nicht mehr kommentiert wird.

Bisher gab es keine praktikable Lösung für dieses Problem, außer "Lassen Sie es sein Ding machen und dann alle Probleme von Hand beheben", und das ist, um ehrlich zu sein, ein bisschen fubar.

Hier ist ein Bild, das das Problem verdeutlicht:

[Originalbild verloren]

Die Dateien C & E (oder Änderungen C & E) dürfen nur in Zweig b und nicht in Zweig a angezeigt werden. Revision A9 hier (Zweig a, Revno 9) ist der Beginn des Problems.

Die Revisionen A10 und A11 sind die Phasen "Backout Merge" und "Merge the Backout".

Und Revision B12 ist quecksilberhaltig und löscht fälschlicherweise wiederholt eine Änderung, die nicht gelöscht werden sollte.

Dieses Dilemma hat viel Frust und blauen Rauch verursacht und ich möchte dem ein Ende setzen.

Hinweis

Es kann die offensichtliche Antwort zu versuchen , die umgekehrte merge Verbot auftritt, entweder mit Haken oder mit Politik, ich habe die Fähigkeit hat dieses bis mucken ist ziemlich hoch und die Chance, es passiert so wahrscheinlich , dass auch mit Gegenmaßnahmen, Sie müssen noch Nehmen Sie an, dass dies unweigerlich passieren wird , damit Sie es lösen können, wenn dies der Fall ist.

Ausarbeiten

Im Modell habe ich separate Dateien verwendet. Dadurch klingt das Problem einfach. Diese stellen lediglich willkürliche Änderungen dar, die eine separate Zeile sein können.

Um die Verletzung zusätzlich zu beleidigen, gab es in Zweig A wesentliche Änderungen, die das ständige Problem hinterlassen. "Machen Sie die Änderungen in Zweig A zu einem Konflikt mit den Änderungen in Zweig B, die gerade aufgetaucht sind (und zurückgesetzt wurden), was wie eine Änderung aussieht stattdessen auf Zweig A "

Über Tricks zum Umschreiben der Geschichte:

Das Problem bei all diesen rückwirkenden Lösungen ist wie folgt:

  1. Wir haben 9000 Commits.
  2. Das frische Klonen dauert somit eine halbe Stunde
  3. Wenn es irgendwo nur einen fehlerhaften Klon des Repositorys gibt, ist es wahrscheinlich, dass er wieder mit dem ursprünglichen Repository in Kontakt kommt und ihn erneut aufschlägt.
  4. Jeder hat dieses Repository bereits geklont, und jetzt sind mehrere Tage mit laufenden Commits vergangen.
  5. Ein solcher Klon ist zufällig eine Live-Site, also "diesen löschen und von vorne anfangen" = "big nono"

(Ich gebe zu, viele der oben genannten sind etwas dumm, aber sie liegen außerhalb meiner Kontrolle).

Die einzigen Lösungen, die realisierbar sind, sind diejenigen, die davon ausgehen, dass Menschen alles falsch machen können und werden und dass es einen Weg gibt, diese Ungerechtigkeit rückgängig zu machen.


1
Autsch, das sieht hässlich aus ... Hast du das auch auf selenic.com/mercurial/bts gepostet ? Dies klingt wie ein Hg-Fehler, der behoben werden sollte.
Mike G.

4
Entschuldigung an alle, das Image-Hosting ging unter :( und ich kann keine Origianls finden
Kent Fredric

1
Gibt es Neuigkeiten zu diesem Thema, nur aus Interesse, nach 2 Jahren Entwicklung würde ich gerne glauben, dass es jetzt bessere Möglichkeiten gibt, damit umzugehen? :)
Pete Duncanson

Kann man verstehen, dass der Zweig 'A' QA / Prod und 'B' Main / Dev ist?
Schlitten

Antworten:


50

Ich glaube, ich habe eine Lösung gefunden, die die fehlerhafte Zusammenführung dauerhaft behebt und bei der Sie keine Unterschiede manuell überprüfen müssen. Der Trick besteht darin, in die Geschichte zurückzugehen und Commits parallel zur fehlerhaften Zusammenführung zu generieren.

Wir haben also ein Repository mit separaten Zweigen pro gepflegter Version eines einzelnen Produkts. Wie die in der Frage gestellte Situation müssen alle Änderungen, die an einem Zweig einer früheren Version vorgenommen wurden (dh die Bugfixes für diese Version), schließlich mit den Zweigen der späteren Versionen zusammengeführt werden.

Wenn also etwas in BRANCH_V8 eingecheckt ist, muss es mit BRANCH_V9 zusammengeführt werden.

Jetzt macht einer der Entwickler folgenden Fehler: Er führt alle Änderungen von BRANCH_V9 in BRANCH_V8 zusammen (dh eine Zusammenführung in die falsche Richtung). Darüber hinaus führt er nach dieser schlechten Zusammenführung einige zusätzliche Commits durch, bevor er seinen Fehler bemerkt.

Die Situation ist also wie im folgenden grafischen Protokoll dargestellt.

o BRANCH_V8 - 13 - wichtiges Commit direkt nach der fehlerhaften Zusammenführung
|
o BRANCH_V8 - 12 - Falsche Zusammenführung von BRANCH_V9
| \
| o BRANCH_V8 - 11 - Kommentar zu BRANCH_V8 hinzufügen (dh letzter bekannter guter Zustand)
| |
o | BRANCH_V9 - 10 - letztes Commit für BRANCH_V9
| |

Wir können diesen Fehler wie folgt beheben:

  1. Aktualisieren Sie Ihr lokales Verzeichnis auf den letzten guten Zustand von BRANCH_V8: hg update 11
  2. Erstellen Sie ein neues Kind dieses letzten guten Zustands:
    1. Ändern Sie eine Datei $EDITOR some/file.txt(dies ist erforderlich, da Mercurial keine leeren Commits zulässt.)
    2. Übernehmen Sie diese Änderungen. hg commit -m "generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9"
      Die Situation sieht nun wie folgt aus:
      o BRANCH_V8 - 14 - Generieren eines Commits für BRANCH_V8, um eine falsche Zusammenführung von BRANCH_V9 zu korrigieren
      |
      | o BRANCH_V8 - 13 - wichtiges Commit direkt nach der fehlerhaften Zusammenführung
      | |
      | o BRANCH_V8 - 12 - Falsche Zusammenführung von BRANCH_V9
      | / |
      o | BRANCH_V8 - 11 - Kommentar zu BRANCH_V8 hinzufügen
      | |
      | o BRANCH_V9 - 10 - letztes Commit für BRANCH_V9
      
  3. Führen Sie den neu generierten Kopf mit der Revision zusammen, in der die fehlerhafte Zusammenführung stattgefunden hat, und werfen Sie alle Änderungen weg, bevor Sie sie festschreiben. Führen Sie die beiden Köpfe nicht einfach zusammen, da Sie dann das wichtige Commit verlieren, das auch nach dem Zusammenführen stattgefunden hat!

    1. Zusammenführen: hg merge 12(Konflikte ignorieren)
    2. alle Änderungen wegwerfen: hg revert -a --no-backup -r 14
    3. hg commit -m "throwing away wrong merge from BRANCH_V9" Übernehmen Sie die Änderungen: Die Situation sieht jetzt so aus:
      o BRANCH_V8 - 15 - falsche Zusammenführung von BRANCH_V9 wegwerfen
      | \
      | o BRANCH_V8 - 14 - Generieren eines Commits für BRANCH_V8, um eine falsche Zusammenführung von BRANCH_V9 zu korrigieren
      | |
      + --- o BRANCH_V8 - 13 - wichtiges Commit direkt nach der fehlerhaften Zusammenführung
      | |
      o | BRANCH_V8 - 12 - Falsche Zusammenführung von BRANCH_V9
      | \ |
      | o BRANCH_V8 - 11 - Kommentar zu BRANCH_V8 hinzufügen
      | |
      o | BRANCH_V9 - 10 - letztes Commit für BRANCH_V9
      | |
      

    Dh. Es gibt zwei Köpfe in BRANCH_V8: einen, der die Korrektur der fehlerhaften Zusammenführung enthält, und den anderen, der das übrig gebliebene wichtige Commit für BRANCH_V8 enthält, das unmittelbar nach der Zusammenführung stattgefunden hat.

  4. Füge die beiden Köpfe auf BRANCH_V8 zusammen:
    1. zusammenführen: hg merge
    2. verpflichten : hg commit -m "merged two heads used to revert from bad merge"

Die Situation am Ende von BRANCH_V8 ist jetzt korrigiert und sieht folgendermaßen aus:

o BRANCH_V8 - 16 - zwei Köpfe zusammengeführt, die verwendet wurden, um von einer schlechten Zusammenführung zurückzukehren
| \
| o BRANCH_V8 - 15 - falsche Zusammenführung von BRANCH_V9 wegwerfen
| | \
| | o BRANCH_V8 - 14 - Generieren eines Commits für BRANCH_V8, um eine falsche Zusammenführung von BRANCH_V9 zu korrigieren
| | |
o | | BRANCH_V8 - 13 - wichtiges Commit direkt nach der fehlerhaften Zusammenführung
| / /
o | BRANCH_V8 - 12 - Falsche Zusammenführung von BRANCH_V9
| \ |
| o BRANCH_V8 - 11 - Kommentar zu BRANCH_V8 hinzufügen
| |
o | BRANCH_V9 - 10 - letztes Commit für BRANCH_V9
| |

Jetzt ist die Situation auf BRANCH_V8 korrekt. Das einzige verbleibende Problem ist, dass die nächste Zusammenführung von BRANCH_V8 zu BRANCH_V9 falsch ist, da sie auch im 'Fix' für die fehlerhafte Zusammenführung zusammengeführt wird, was wir bei BRANCH_V9 nicht wollen. Der Trick hier besteht darin, in separaten Änderungen von BRANCH_V8 zu BRANCH_V9 zusammenzuführen:

  • Führen Sie zuerst von BRANCH_V8 zu BRANCH_V9 die korrekten Änderungen an BRANCH_V8 vor der fehlerhaften Zusammenführung zusammen.
  • Beim zweiten Zusammenführen des Zusammenführungsfehlers und seiner Korrektur werden alle Änderungen verworfen, ohne dass etwas überprüft werden muss
  • Drittens die verbleibenden Änderungen von BRANCH_V8 zusammenführen.

Im Detail:

  1. Wechseln Sie Ihr Arbeitsverzeichnis zu BRANCH_V9: hg update BRANCH_V9
  2. Zusammenführen im letzten guten Zustand von BRANCH_V8 (dh dem Commit, das Sie generiert haben, um die schlechte Zusammenführung zu beheben). Diese Zusammenführung ist eine Zusammenführung wie jede reguläre Zusammenführung, d. H. Konflikte sollten wie gewohnt gelöst werden und nichts muss weggeworfen werden.
    1. zusammenführen: hg merge 14
    2. Commit: hg commit -m "Merging in last good state of BRANCH_V8" Die Situation ist jetzt:
      @ BRANCH_V9 - 17 - Zusammenführen im letzten guten Zustand von BRANCH_V8
      | \
      | | o BRANCH_V8 - 16 - zwei Köpfe zusammengeführt, die verwendet wurden, um von einer schlechten Zusammenführung zurückzukehren
      | | | \
      | + --- o BRANCH_V8 - 15 - falsche Zusammenführung von BRANCH_V9 wegwerfen
      | | | |
      | o | | BRANCH_V8 - 14 - Generieren eines Commits für BRANCH_V8, um eine falsche Zusammenführung von BRANCH_V9 zu korrigieren
      | | | |
      | | o | BRANCH_V8 - 13 - wichtiges Commit direkt nach der fehlerhaften Zusammenführung
      | | | /
      + --- o BRANCH_V8 - 12 - falsche Zusammenführung von BRANCH_V9
      | | /
      | o BRANCH_V8 - 11 - Kommentar zu BRANCH_V8 hinzufügen
      | |
      o | BRANCH_V9 - 10 - letztes Commit für BRANCH_V9
      | |
      
  3. Führen Sie die fehlerhafte Zusammenführung von BRANCH_V8 + seiner Korrektur zusammen und werfen Sie alle Änderungen weg:
    1. zusammenführen: hg merge 15
    2. Alle Änderungen rückgängig machen: hg revert -a --no-backup -r 17
    3. Zusammenführen festschreiben: hg commit -m "Merging in bad merge from BRANCH_V8 and its fix and throwing it all away" Aktuelle Situation:
      @ BRANCH_V9 - 18 - Zusammenführen von BRANCH_V8 und seiner Korrektur in schlechter Verbindung und alles wegwerfen
      | \
      | o BRANCH_V9 - 17 - Zusammenführen im letzten guten Zustand von BRANCH_V8
      | | \
      + ----- o BRANCH_V8 - 16 - zwei Köpfe zusammengeführt, die verwendet wurden, um von einer schlechten Zusammenführung zurückzukehren
      | | | |
      o --- + | BRANCH_V8 - 15 - falsche Zusammenführung von BRANCH_V9 wegwerfen
      | | | |
      | | o | BRANCH_V8 - 14 - Generieren eines Commits für BRANCH_V8, um eine falsche Zusammenführung von BRANCH_V9 zu korrigieren
      | | | |
      + ----- o BRANCH_V8 - 13 - wichtiges Commit direkt nach der fehlerhaften Zusammenführung
      | | |
      o --- + BRANCH_V8 - 12 - falsche Zusammenführung von BRANCH_V9
      | / /
      | o BRANCH_V8 - 11 - Kommentar zu BRANCH_V8 hinzufügen
      | |
      o | BRANCH_V9 - 10 - letztes Commit für BRANCH_V9
      | |
      
  4. Führen Sie die verbleibenden Änderungen von BRANCH_V8 zusammen:
    1. zusammenführen: hg merge BRANCH_V8
    2. verpflichten : hg commit -m "merging changes from BRANCH_V8"

Am Ende sieht die Situation so aus:

@ BRANCH_V9 - 19 - Zusammenführen von Änderungen von BRANCH_V8
| \
| o BRANCH_V9 - 18 - Zusammenführen von BRANCH_V8 und seiner Korrektur in schlechter Verbindung und alles wegwerfen
| | \
| | o BRANCH_V9 - 17 - Zusammenführen im letzten guten Zustand von BRANCH_V8
| | | \
o | | | BRANCH_V8 - 16 - hat zwei Köpfe zusammengeführt, die verwendet wurden, um von einer schlechten Zusammenführung zurückzukehren
| \ | | |
| o --- + BRANCH_V8 - 15 - falsche Zusammenführung von BRANCH_V9 wegwerfen
| | | |
| | | o BRANCH_V8 - 14 - Generieren eines Commits für BRANCH_V8, um eine falsche Zusammenführung von BRANCH_V9 zu korrigieren
| | | |
o | | | BRANCH_V8 - 13 - wichtiges Commit direkt nach der fehlerhaften Zusammenführung
| / / /
o --- + BRANCH_V8 - 12 - falsche Zusammenführung von BRANCH_V9
| / /
| o BRANCH_V8 - 11 - Kommentar zu BRANCH_V8 hinzufügen
| |
o | BRANCH_V9 - 10 - letztes Commit für BRANCH_V9
| |

Nach all diesen Schritten, in denen Sie keinen Unterschied manuell überprüfen müssen, sind BRANCH_V8 und BRANCH_V9 korrekt, und zukünftige Zusammenführungen von BRANCH_V8 zu BRANCH_V9 sind ebenfalls korrekt.


Grundsätzlich besteht der Vorteil dieser Methode darin, dass Sie ein Commit (in diesem Fall Version 15) generieren, das ab dem letzten guten Punkt in BRANCH_V8 nur die fehlerhafte Zusammenführung und deren Korrektur enthält. Sie können diesen Änderungssatz dann separat in BRANCH_V9 zusammenführen und alle Änderungen, die mit dieser Zusammenführung einhergehen, ignorieren.
Oenli

1
Ahhhh, </pre>nach dem vorletzten Codeblock fehlte etwas. Es hat eine Weile gedauert, bis ich gefunden habe, aber gerade als ich bereit war aufzugeben ... Jetzt wird alles richtig angezeigt, denke ich :)
etw

Beachten Sie, dass für Git dieselbe Technik verwendet werden kann, sodass Sie die Rückwärtszusammenführung korrigieren können, ohne den Verlauf neu zu schreiben, was zu Kopfschmerzen führt.
Oenli

4
Das ist toll. Vielen Dank. Bevor Sie dies tun, sollte @Kent einen Commit-Hook installieren, der verhindert, dass Rückwärts-Merges festgeschrieben und / oder gepusht werden. Beheben Sie die Grundursache des Problems und beheben Sie dann die verbleibenden Symptome.
Harvey

1
Ich habe eine Hg - Repository erstellt , diese Lösung zu demonstrieren (ohne die zusätzliche leer begehen) bitbucket.org/janverley/wrongmerge
jan

2

Zur Not können Sie das Repository in eine Reihe von Unterschieden exportieren, den Verlauf bearbeiten und dann genau das wieder zusammenkleben, was Sie möchten - in ein neues Repository, sodass kein Risiko einer Beschädigung besteht. Wahrscheinlich nicht schlecht für Ihr Beispiel, aber ich weiß nicht, wie die wahre Geschichte aussieht.

Ich habe auf diese Seite verwiesen, während ich eine einfachere Operation ausgeführt habe:

http://strongdynamic.blogspot.com/2007/08/expunging-problem-file-from-mercurial.html


Ja, es wäre ein erschöpfender Prozess, das zu tun, was Sie getan haben, und es würde nicht unbedingt für meine Situation funktionieren (benannte Zweige funktionieren merkwürdig), und die Geschichte ist ein Schweinestall, wenn Sie dort> 4 Committer haben, die alle ihren eigenen Zeitplan haben ist überhaupt keine Linearität;)
Kent Fredric

2

OK, erstellen Sie zunächst ein neues leeres Repository in einem vom kaputten Repository getrennten Verzeichnis (hg init). Rufen Sie nun die letzte bekannte gute Version auf und fügen Sie sie in das neue Repository ein. stellen Sie sicher , nicht das schlechte Zusammenführung ziehen und tun Pull alles vor sich her. Aktualisieren Sie im alten Repository auf die letzte bekannte gute Version von A und gehen Sie folgendermaßen vor:

hg graft r1 r2 r3

Dabei sind r1-3 Änderungen, die nach der verpfuschten Zusammenführung vorgenommen wurden. An dieser Stelle können Konflikte auftreten. repariere sie.

Dies sollte neue Änderungen gegenüber der letzten bekannten guten Version von A hervorrufen . Ziehen Sie diese neuen Änderungen in das neue Repository. Um zu überprüfen, ob Sie nichts verpasst haben, führen Sie einen HG-Eingang für das alte Repository durch. Wenn Sie etwas anderes als die verpfuschte Zusammenführung und r1-3 sehen, ziehen Sie daran.

Werfen Sie das alte Repository weg. Du bist fertig. Die Zusammenführung befindet sich überhaupt nicht im neuen Repository und Sie mussten den Verlauf nie neu schreiben.


1

Sie möchten also nur einige Änderungssätze von B in A zusammenführen? Das Zurücksetzen von Änderungssätzen wie bisher ist eine wirklich schlechte Idee, da Sie bereits gelitten haben.

Sie sollten entweder die Transplantatverlängerung verwenden oder einen dritten Zweig haben, in dem Sie allgemeine Änderungen vornehmen, um sowohl A als auch B zusammenzuführen.


2
Änderungen nicht zurücksetzen, weil ich / möchte / hier;), und das Problem ist, egal wie viele Zweige ich erstelle, es ist immer noch möglich , sie falsch zusammenzuführen, was dieses Problem verursacht. (Vertrau mir, war auf dieser Straße)
Kent Fredric

1

Nach vielen Diskussionen mit einigen der hilfreichen Leute auf #mercurial on freenode hat mpm eine Teillösung bereitgestellt , die für meinen Testfall zu funktionieren scheint (ich habe ein gefälschtes Repository generiert, das versucht, das Szenario zu replizieren).

In meinem eigentlichen Repository ist es jedoch aus Gründen, die ich nicht ganz verstehe, immer noch nicht perfekt.

Hier ist ein Diagramm der derzeit vorgeschlagenen Methode zur Lösung dieses Problems:

[Originalbild verloren]

Es ist jetzt weniger ein Problem zu beheben, aber ich muss immer noch Unterschiede vergleichen (dh: b46: b11 gegen b46: b8, a43: a10 gegen a43: a9) und einige Änderungen von Hand bearbeiten.

Diese Frage nicht schließen / eine Antwort nehmen, bis ich eine garantierte Methode erhalte, die in jedem Repository funktioniert.

Wichtig

Jeder, der dieses Zeug ausprobiert, sollte sein Repository klonen und zuerst wie eine Sandbox damit spielen. Wie Sie es bei jedem Zusammenführungsprozess tun sollten , denn wenn es schief geht, können Sie es einfach wegwerfen und von vorne beginnen.

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.