Wie stellt man den linearen Git-Verlauf nach einer nichtlinearen Zusammenführung wieder her?

Lesezeit: 6 Minuten

Benutzeravatar von ruohola
Ruohola

Vor ein paar Commits habe ich versehentlich eine nichtlineare Zusammenführung in meinem Master-Zweig durchgeführt. Ich habe die Angewohnheit, immer zu versuchen, eine lineare Geschichte zu führen, also möchte ich jetzt die Linearität wiederherstellen.

Ich habe ein Dummy-Repo erstellt, das die reale Situation simuliert, die ich habe, um dies einfacher zu machen. Hier ist ein GitHub-Link dazu: https://github.com/ruohola/merge-question

Hier ist die Ausgabe von git log --oneline --graph --date-order:

* 88a4b7e (HEAD -> master, origin/master, origin/HEAD) 11
* 5aae63c 10
*   5506f33 Merge branch 'other'
|\
| * b9c56c9 9
* | 3c72a2a 8
| * 8d2c1ea 7
| * 35f124b 6
* | 7ca5bc1 5
* | b9e9776 4
| * fd83f02 3
|/
* 4fa8b2e 2
* cbdcf50 1

Gleiches Diagramm in Sourcetree:

git melde dich im Quellbaum an

Und hier ist eine Mspaint-Visualisierung, wie ich meinen Master aussehen lassen möchte – es sollte im Wesentlichen so sein, als hätte ich vor der Zusammenführung rebasiert:
(Die Hashes würden sich ändern)

gewünschtes Endergebnis

Ich weiß, dass dies möglicherweise nicht die beste Vorgehensweise ist, und ich bin mit den Folgen des Umschreibens der Geschichte vertraut (obwohl niemand sonst an diesem Zweig arbeitet), würde dies aber dennoch tun wollen. Wie kann dies erreicht werden?

  • Obwohl dies gegen allgemeine Git-Praktiken verstößt, werde ich nicht hinterfragen, warum Sie a wollen strikt lineare Geschichte, aber was Sie tun können, ist, Ihre Commits herauszupicken, oder Sie können dies tun

    – mnestorov

    2. August 2019 um 14:33 Uhr

Benutzeravatar von eftshift0
eftshift0

Ich denke, es ist nicht so schwer, denken Sie nur daran, dass die Geschichte des Meisters neu geschrieben werden muss:

git checkout b9c56c9
git rebase 3c72a2a # rebase on top of the other branch
git cherry-pick 5506f33..master # reapply changes from merge revision (dropping it) up until the tip of master
# if you like the results
git branch -f master
git checkout master

Und jetzt könnten Sie den Zweig zwangsschieben, wenn Sie den bereits haben alt Master in einer anderen Fernbedienung

  • Es tut mir leid, dass ich Ihre Antwort nicht akzeptieren musste, da ich einen äußerst einfachen Weg gefunden habe, dies zu erreichen.

    – Ruola

    18. Februar 2020 um 9:57 Uhr

Benutzeravatar von ruohola
Ruohola

Der vielleicht einfachste Weg, dies zu tun, besteht darin, das Standardverhalten von zu “missbrauchen”. git rebase. Das heißt, ohne ausdrücklich zu übergeben --rebase-merges zu git rebase, werden tatsächlich alle Merge-Commits aus dem Verlauf entfernt. So kommen wir ganz einfach zum gewünschten Ergebnis:

Vor:

~/merge-question (master) $ git log --oneline --graph --date-order
* 88a4b7e (HEAD -> master, origin/master, origin/HEAD) 11
* 5aae63c 10
*   5506f33 Merge branch 'other'
|\
| * b9c56c9 9
* | 3c72a2a 8
| * 8d2c1ea 7
| * 35f124b 6
* | 7ca5bc1 5
* | b9e9776 4
| * fd83f02 3
|/
* 4fa8b2e 2
* cbdcf50 1

Ausführen des Befehls:

~/merge-question (master) $ git rebase 3c72a2a
First, rewinding head to replay your work on top of it...
Applying: 3
Applying: 6
Applying: 7
Applying: 9
Applying: 10
Applying: 11

Nach:

~/merge-question (master) $ git log --oneline --graph --date-order
* d72160d (HEAD -> master) 11
* 90a4718 10
* 3c773db 9
* ba00ecf 7
* 9e48199 6
* 24376c7 3
* 3c72a2a 8
* 7ca5bc1 5
* b9e9776 4
* 4fa8b2e 2
* cbdcf50 1

Danach nur ein einfaches git push --force-with-lease origin master und der Verlauf der Fernbedienung ist wieder linear.

  • Ich glaube, ich verstehe nicht, wie das genau funktioniert, aber die Lösung ist nett und hat sich als sehr hilfreich erwiesen!

    – Nr

    2. November 2020 um 18:29 Uhr

  • Dies scheint die einfachste Lösung zu sein,

    – sol

    16. Februar 2021 um 9:25 Uhr

Ein Ansatz wäre die Verwendung von Rebase.

Unabhängig davon, welchen Ansatz Sie wählen, Sie Wille müssen Sie die Historie Ihres Repositorys neu schreiben. Das musst du akzeptieren, sonst musst du deine aktuelle Geschichte akzeptieren.

Lassen Sie uns die verschiedenen Abschnitte Ihrer Geschichte zusammenfassen:

  • Commit 4, 5 und 8, diese befinden sich auf dem Master
  • Commit 3, 6, 7 und 9, diese liegen jetzt auch auf master, waren aber ursprünglich auf einem anderen Branch
  • Commit 10 und 11 befinden sich auf Master, nachdem Sie die beiden parallelen Historien oben zusammengeführt haben

Um das zu lösen, würde ich wie folgt vorgehen:

  1. Überprüfen Sie den “ursprünglichen Zweig”, dh Commit-Nr. 9
  2. Erstellen Sie hier einen neuen Zweig, nur um sicherzustellen, dass wir ein bisschen herumspielen können
  3. Basieren Sie diesen neuen Zweig (bestehend aus den Commits 3, 6, 7 und 9) sozusagen über dem Master, als Sie ihn ursprünglich zusammengeführt haben, also über Commit 8
  4. Lösen Sie alle Merge-Konflikte auf (Sie haben diese auch beim ursprünglichen Merge erhalten, aber sie müssen jetzt möglicherweise anders gehandhabt werden, da die Rebase im Vergleich zum Merge funktioniert).
  5. Wenn Sie dies getan haben, sehen Sie sich das letzte an früher commit auf master, das ist 11, und rebasiere Commit 10 und 11 auf deinem neuen Branch
  6. Wenn alles jetzt gut aussieht, können Sie den Master hart auf diesen neuen Zweig zurücksetzen und auf Ihre Fernbedienung drücken, um ihn zum neuen Verlauf zu machen

Hier sind Diagramme des Prozesses, Schritt für Schritt (Befehle folgen):

Stand jetzt:

                         master
                            v
1---2---4---5---8---M--10--11
     \             /
      3---6---7---9

Neuer Zweig für 9:

                         master
                            v
1---2---4---5---8---M--10--11
     \             /
      3---6---7---9
                  ^
                TEMP1

Rebase auf 8, das erzeugt 3′, 6′, 7′, 9′ (the ' bedeutet “Kopie des Commit, gleicher Inhalt, neuer Hash”)

                            TEMP1
                              v
                  3'--6'--7'--9'
                 /
1---2---4---5---8---M--10--11
     \             /        ^
      3---6---7---9      master

Erstellen Sie einen neuen Zweig für 11 (ich mag es nicht, mich mit dem Meister anzulegen)

                            TEMP1
                              v
                  3'--6'--7'--9'
                 /
1---2---4---5---8---M--10--11
     \             /        ^
      3---6---7---9      master
                            ^
                          TEMP2

Rebasieren Sie diesen Zweig (10 und 11) auf TEMP1:

                            TEMP1   TEMP2
                              v       v
                  3'--6'--7'--9'-10'-11'
                 /
1---2---4---5---8---M--10--11
     \             /        ^
      3---6---7---9      master

Stellen Sie sicher, dass TEMP2 mit dem aktuellen Master identisch ist, nichts verloren geht, nichts hinzugefügt wird usw.

Setzen Sie dann den Master auf TEMP2 zurück:

                                    master
                                      v
                            TEMP1   TEMP2
                              v       v
                  3'--6'--7'--9'-10'-11'
                 /
1---2---4---5---8---M--10--11
     \             /
      3---6---7---9

Ich würde dann die Zweige TEMP1 und TEMP2 löschen.

Beachten Sie, dass Commit 3, 6, 7, 9, M, 10 und 11 noch im Repository vorhanden sind, aber nicht direkt verfügbar sind, da nichts auf sie verweist. Sie sind daher für die Garbage Collection geeignet und in Wirklichkeit sieht der tatsächliche Verlauf Ihres Repositorys jetzt so aus:

1---2---4---5---8---3'--6'--7'--9'-10'-11'
                                        ^
                                     master

Die Befehle zum Ausführen dieser Operationen sind:

(Schritt 0: Erstellen Sie eine vollständige Kopie Ihres lokalen Ordners, komplett mit Arbeitsordner und .git-Repository, dann, wenn Sie können, führen Sie die folgenden Befehle in dieser Kopie aus, wenn Sie es vermasseln, löschen Sie die Kopie und beginnen Sie von vorne, Springen Sie nicht ohne Sicherheitsnetz)

  1. git checkout <HASH-OF-9>
  2. git checkout -b TEMP1 (Ja, Sie können dies und den vorherigen Befehl in einem Befehl mit ausführen git checkout -b TEMP1 <HASH-OF-9>)
  3. git rebase -i --onto <HASH-OF-8> <HASH-OF-2> TEMP1
  4. Merge-Konflikte lösen und Commit durchführen, falls vorhanden
  5. git checkout -b TEMP2 <HASH-OF-11>
    git rebase --onto TEMP1 <HASH-OF-MERGE> TEMP2
  6. Überprüfen Sie, ob alles in Ordnung ist
  7. git checkout master
    git reset --hard TEMP2

Endlich aufräumen:

git branch -d TEMP1 TEMP2
git push -f

Drücken Sie nur, wenn Sie wissen, dass alles in Ordnung ist

1429650cookie-checkWie stellt man den linearen Git-Verlauf nach einer nichtlinearen Zusammenführung wieder her?

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

Privacy policy