Das Zusammenführen eines Zweigs eines Zweigs nach dem ersten Zweig wird beim Zusammenführen mit dem Master gequetscht

79

Hier ist ein Workflow, mit dem ich mich normalerweise bei der Arbeit beschäftige.

git checkout -b feature_branch
# Do some development
git add .
git commit
git push origin feature_branch

Zu diesem Zeitpunkt steht der Feature-Zweig zur Überprüfung durch meine Kollegen zur Verfügung, aber ich möchte mich weiter auf andere Features konzentrieren, die davon abhängig sind feature_branch. Also, während feature_branchim Rückblick ...

git checkout feature_branch
git checkout -b dependent_branch
# Do some more development
git add .
git commit

Jetzt nehme ich einige Änderungen als Antwort auf die Codeüberprüfung auf feature_branch vor

git checkout feature_branch
# Do review fixes
git add .
git commit
git checkout dependent_branch
git merge feature_branch

Hier bekommen wir Probleme. Wir haben eine Squash-Richtlinie für Master, was bedeutet, dass Feature-Zweige, die zu Master zusammengeführt werden, zu einem einzigen Commit gequetscht werden müssen.

git checkout feature_branch
git log # Look for hash at beginning of branch
git rebase -i  first_hash_of_branch # Squash feature_branch into a single commit
git merge master

Alles ist cool, außer mit dependent_branch. Wenn ich versuche, abhängige Zweige auf Master umzustellen oder Master darin zusammenzuführen, wird Git durch die neu geschriebene / gequetschte Historie verwirrt und markiert im Grunde jede einzelne Änderung depedendent_branchals Konflikt. Es ist eine PITA, alle Änderungen in zu durchlaufen und im Grunde genommen zu wiederholen oder zu konfliktisieren dependent_branch. Gibt es eine Lösung dafür? Manchmal erstelle ich manuell einen Patch und wende ihn von einem neuen Master-Zweig aus an. Wenn es jedoch echte Konflikte gibt, ist es noch schlimmer, ihn zu beheben.

git checkout dependent_branch
git diff > ~/Desktop/dependent_branch.diff
git checkout master
git checkout -b new_dependent_branch
patch -p1 < ~/Desktop/dependent_branch.diff
# Pray for a clean apply.

Irgendwelche Ideen? Ich weiß, dass dies aufgrund der neu geschriebenen Geschichte während des Squashs passiert, aber das ist eine Voraussetzung, die ich nicht ändern kann. Was ist die beste Lösung / Problemumgehung? Kann ich etwas zaubern? Oder gibt es eine schnellere Möglichkeit, alle Schritte zum manuellen Erstellen des Diff auszuführen?

Mike
quelle
Abgesehen davon git add .ist es völlig böse und wird dich irgendwann beißen, wenn du Dinge begehst, die du nicht vorhast. Sie sollten verwenden git add -poder zumindestgit add -u .
meagar
1
Sie sollten abhängige_Zweig auf den Feature-Zweig umbasieren, sobald Sie Änderungen an der Codeüberprüfung vorgenommen haben. Wenn Sie bereit sind, zum Master zu wechseln, setzen Sie den Feature-Zweig erneut auf den Master, quetschen Sie die Commits und führen Sie den Feature-Zweig zum Master zusammen.
Tim

Antworten:

104

Ein bisschen darüber, warum das passiert:

Ich werde O"ursprünglicher Master" und FB"neuer Master" sein, nachdem ein Feature-Zweig zusammengeführt wurde in:

Say feature_branchsieht aus wie:

O - A - B - C 

dependent_feature hat noch ein paar zusätzliche Commits:

O - A - B - C - D - E - F

Sie führen Ihren ursprünglichen Feature-Zweig zu Master zusammen und drücken ihn zusammen, um Folgendes zu erhalten:

O - FB

Wenn Sie nun versuchen, den abhängigen Zweig neu zu gründen, wird git versuchen, den gemeinsamen Vorfahren zwischen diesen Zweigen herauszufinden. Während es ursprünglich gewesen wäre C, wenn Sie die Commits nicht niedergeschlagen hätten, findet git stattdessen Oals gemeinsamen Vorfahren. Als Ergebnis git versucht zu wiederholen A, Bund Cdie sind bereits enthalten ist in FB, und Sie werden eine Reihe von Konflikten zu bekommen.

Aus diesem Grund können Sie sich nicht wirklich auf einen typischen Rebase-Befehl verlassen, und Sie müssen dies genauer angeben, indem Sie den folgenden --ontoParameter angeben :

git rebase --onto master HEAD~3  # instruct git to replay only the last
                                 # 3 commits, D E and F, onto master.

Ändern Sie den HEAD~3Parameter nach Bedarf für Ihre Zweige, und Sie sollten sich nicht mit redundanter Konfliktlösung befassen müssen.

Eine alternative Syntax, wenn Sie keine Bereiche angeben möchten und Ihren ursprünglichen Feature-Zweig noch nicht gelöscht haben:

git rebase --onto master feature_branch dependent_feature

                                 # replay all commits, starting at feature_branch
                                 # exclusive, through dependent_feature inclusive 
                                 # onto master
joshtkling
quelle
Ich hatte gehofft zu sehen, wie sich der Git-Baum für Master bei der Verwendung von --onto unterscheidet. Oder vielleicht eine andere Möglichkeit, ein bisschen mehr darüber zu verstehen, wie --onto anders ist.
Abhishek Anand
3
Mit --onto können Sie einfach selektiver festlegen, welche Commits Sie in einem Zweig wiedergeben möchten. Standardmäßig versucht git herauszufinden, welche Commits wiederholt werden sollen. Wenn Sie --onto verwenden, weisen Sie git ausdrücklich an, einen bestimmten Bereich von Commits wiederzugeben . Wenn Sie in meinem Beispiel --onto nicht verwenden würden, würden Sie O - FB - A - B - C - D - E - F und zahlreiche Zusammenführungskonflikte erhalten, da FB und A - B - C dieselben Änderungen enthalten. Wenn Sie --onto verwenden und die letzten 3 Commits angeben, erhalten Sie O - FB - D - E - F, wie es der ursprüngliche Fragesteller gesucht hat.
Joshtkling
2

In diesem speziellen Fall scheinen Sie "zu wissen", dass nur die gequetschte Arbeit des Zweigs, an dem Sie ursprünglich gearbeitet haben, in den Master übernommen wurde.

Sie können also problemlos zusammenführen, indem Sie Ihre Änderungen jedes Mal beibehalten, wenn ein Konflikt vorliegt. Dafür gibt es eine Option:

git merge -Xours master

Weitere Informationen finden Sie unter https://git-scm.com/docs/git-rebase .

nha
quelle
1
Dies kann leider nicht der Fall sein. Wenn zwischen den Codeüberprüfungen für feature_branch und abhängige_Zweige Zeit liegt, wird die feature_branch möglicherweise zusammengeführt und verschoben, und jemand anderes fügt möglicherweise Konflikte hinzu, bevor die abhängige_Zweige gelandet ist.
Mike
0

Ich bin von Herzen anderer Meinung als die Richtlinie "Jede Feature-Entwicklung in einem einzigen Commit zusammenfassen", aber es ist ihr Aufruf ...

Ich würde die Zweige unverändert lassen und ein zusammengesetztes Commit nur zur Veröffentlichung in einem speziellen Zweig erstellen. Es ist wertvoll, die Entwicklung Schritt für Schritt verfolgen zu können, auch wenn das Management nicht daran glaubt. Markieren Sie die Stellen von Squashes durch Tags in den "echten" Zweigen. Sie können auch Tags zwischen Squashs mit Nachrichten hinzufügen, die auf die realen Commits verweisen.

vonbrand
quelle
Eigentlich mag ich dieses Squashing, aber das liegt daran, dass es tatsächlich von Arccanist gemacht wird und die gesamte Entwicklung / Commits / Code-Überprüfung für einen Feature-Zweig in Phabricator gespeichert ist ... aber ich verstehe Ihren Standpunkt mit Sicherheit.
Mike