Bricht Squashing Pull Requests den Merge-Algorithmus von Git?

14

Ich arbeite derzeit für eine Firma, die VSTS für die Verwaltung von Git-Code verwendet. Die von Microsoft empfohlene Methode zum Zusammenführen eines Zweigs besteht darin, einen "Squash-Merge" durchzuführen. Dies bedeutet, dass alle Festschreibungen für diesen Zweig zu einer neuen Festschreibung zusammengefasst werden, in der alle Änderungen enthalten sind.

Das Problem ist, was passiert, wenn ich einige Änderungen in einer Verzweigung für ein Backlog-Element vornehme und dann sofort Änderungen in einer anderen Verzweigung für ein anderes Backlog-Element vornehmen möchte. Diese Änderungen hängen von den Änderungen der ersten Verzweigung ab?

Ich kann eine Verzweigung für dieses Rückstandselement erstellen und auf der ersten Verzweigung aufbauen. So weit, ist es gut. Wenn es jedoch an der Zeit ist, eine Pull-Anforderung für den zweiten Zweig zu erstellen, wurde der erste Zweig bereits in Master zusammengeführt. Da dies als Squash-Zusammenführung erfolgt, weist git auf eine Reihe von Konflikten hin. Dies liegt daran, dass git die ursprünglichen Commits, auf denen der zweite Zweig basiert, nicht sieht, sondern nur das Zusammenführen eines großen Kürbisses. Um den zweiten Zweig zum Master zusammenzuführen, wird versucht, alle Commits des ersten Zweigs erneut abzuspielen oben auf der Squash-Fusion, was zu vielen Konflikten führt.

Meine Frage ist also, ob es eine Möglichkeit gibt, dies zu umgehen (abgesehen davon, dass ich nie einen Feature-Zweig von einem anderen abstützt, was meinen Workflow einschränkt) oder ob das Zusammenführen von Squash nur den Zusammenführungsalgorithmus von Git unterbricht.

Jez
quelle

Antworten:

15

Mit Git wird ein Commit ausgeführt

  • unveränderlich sind,
  • und bilden einen gerichteten azyklischen Graphen.

Squashing kombiniert keine Commits. Stattdessen zeichnet es ein neues Commit mit den Änderungen aus mehreren anderen Commits auf. Das erneute Reduzieren ist ähnlich, kombiniert jedoch keine Commits. Das Aufzeichnen eines neuen Commits mit denselben Änderungen wie bei einem vorhandenen Commit wird als Umschreiben des Verlaufs bezeichnet . Da jedoch bestehende Commits unveränderlich sind, sollte dies als „Schreiben einer alternativen Geschichte“ verstanden werden.

Beim Zusammenführen wird versucht, die Änderungen der Historien (Zweige) von zwei Commits zu kombinieren, beginnend mit einem gemeinsamen Vorgänger-Commit.

Schauen wir uns also Ihre Geschichte an:

                                 F  feature2
                                /
               1---2---3---4---5    feature1 (old)
              /
-o---o---o---A---o---o---S          master

A ist der gemeinsame Vorfahr, 1–5 der ursprüngliche Feature-Zweig, F der neue Feature-Zweig und S das gequetschte Commit, das die gleichen Änderungen wie 1–5 enthält. Wie Sie sehen können, ist der gemeinsame Vorfahr von F und S A. In Bezug auf git gibt es keine Beziehung zwischen S und 1–5. Das Zusammenführen von Master mit S auf der einen Seite und Feature2 mit 1–5 auf der anderen Seite führt zu Konflikten. Das Lösen dieser Konflikte ist nicht schwierig, aber es ist unnötige, mühsame Arbeit.

Aufgrund dieser Einschränkungen gibt es zwei Ansätze für das Zusammenführen / Zusammenpressen:

  • Entweder verwenden Sie das Umschreiben des Verlaufs. In diesem Fall erhalten Sie mehrere Festschreibungen, die dieselben Änderungen darstellen. Sie würden dann den zweiten Feature-Zweig auf das Squashed-Commit zurückführen :

                                     F  feature2 (old)
                                    /
                   1---2---3---4---5    feature1 (old)
                  /
    -o---o---o---A---o---o---S          master
                              \
                               F'       feature2
    
  • Oder Sie verwenden kein Umschreiben des Verlaufs. In diesem Fall erhalten Sie möglicherweise zusätzliche Merge-Commits:

                                     F  feature2
                                    /
                   1---2---3---4---5    feature1 (old)
                  /                 \
    -o---o---o---A---o---o-----------M  master
    

    Wenn Feature2 und Master zusammengeführt werden, lautet der gemeinsame Vorfahr Commit 5.

In beiden Fällen müssen Sie einige Anstrengungen zum Zusammenführen. Diese Anstrengung hängt nicht sehr stark davon ab, welche der beiden oben genannten Strategien Sie wählen. Aber stellen Sie sicher, dass

  • Zweige sind kurzlebig, um zu begrenzen, wie weit sie vom Hauptzweig abweichen können, und das auch
  • Sie führen Master regelmäßig in Ihrem Feature-Zweig zusammen oder bauen den Feature-Zweig auf Master neu auf, um die Zweige synchron zu halten.

Wenn Sie in einem Team arbeiten, ist es hilfreich zu koordinieren, wer gerade an was arbeitet. Dies trägt dazu bei, die Anzahl der in der Entwicklung befindlichen Features gering zu halten und die Anzahl der Zusammenführungskonflikte zu verringern.

amon
quelle
2
Ihre Antwort scheint nicht das anzugehen, was passiert, wenn Sie zuerst einen Squash-Merge feature1auf den Master durchführen und später einen Merge durchführen möchten feature2. In diesem Fall würde der erste Ansatz nicht zu Konflikten führen, wenn git versucht, die feature1Commits erneut auf das gequetschte Commit anzuwenden , während git mit dem zweiten Ansatz feststellen könnte, dass diese Commits nicht zusammengeführt werden müssen.
Jez
@Jez Genau das passiert, wenn du eine PR quetschst. Ich musste kürzlich eine PR für ein OSS-Projekt manuell umschreiben (indem git cloneich das Repo machte und meine geänderten Dateien kopierte!), Weil ich von einem Zweig abzweigte und dann der Betreuer den ersten Zweig zerquetschte. Bei meiner Arbeit machen sie auch Squash-Merges. Dies bedeutet, dass ich an einer Funktion b, die von der Funktion abhängt, erst arbeiten kann, awenn die Funktion azusammengeführt wird.
Konto
1
Und ist das nicht ein wirklich ärgerlicher Bruch von etwas, das sonst so funktionieren würde, wie es git vorsieht? Ich sehe verschiedene Organisationen wie Microsoft und Github, die diese Squash-Zusammenschlüsse empfehlen, und sie scheinen mir dumm zu sein.
Jez
1
@Jez Im ursprünglichen Szenario kommt es zu Konflikten beim Zusammenführen von Feature2 mit Master, da das Zusammenführen der Commits 1–5 mit den gleichen Änderungen in S in Konflikt steht. Die Lösung besteht darin, Feature2 (Lösung 1) neu zu definieren oder Squashing / Re-Basing bei nicht zu verwenden alle (Lösung 2).
amon
Ob Squash-Zusammenführungen zu Ihnen passen, hängt davon ab, was Sie im Versionskontrollverlauf aufzeichnen möchten. Wenn die Feature-Zweige über viele WIP-Commits verfügen, wird beim Squashing ein einziges großes Commit mit dem vollständigen Feature für den Master-Zweig erstellt. Wenn Sie es vorziehen, alle zwischengeschalteten Commits des Feature-Zweigs beizubehalten, verwenden Sie die Option zum erneuten Basieren oder Zusammenführen.
amon
11

Das Zusammenführen von Squash unterbricht den Zusammenführungsalgorithmus für alle Zweige, die Commits enthalten, die durch den Squash entfernt wurden. Anders ausgedrückt, Rebases sind viral. Wenn Sie einen Zweig neu einrichten, müssen Sie alle anderen Zweige neu einrichten, die von diesem Zweig abhängen. Wenn Sie rerere verwenden , müssen Zusammenführungskonflikte, die Sie manuell in Ihrem lokalen Repo gelöst haben, nicht erneut manuell gelöst werden. Dies hilft jedoch nicht bei Konflikten, die von anderen Personen gelöst wurden.

Aus diesem Grund ist es unsere ungeschriebene Regel, dass es in Ordnung ist, Squash zu spielen, solange niemand sonst jemals von Ihrem Feature-Zweig abhängt, was in etwa 90% der Fälle der Fall ist. Andernfalls hilft eine direkte Zusammenführung allen, Probleme zu vermeiden.

Karl Bielefeldt
quelle
Eine Möglichkeit, sowohl ein Squash-Commit im Master-Verlauf als auch einen Feature-Zweig zu erhalten, um einen separaten Nur-Squash-Zweig zu erstellen. Angenommen, Sie haben eine feature-xyzNiederlassung. Sie können einen feature-xyz-squashedZweig erstellen, der mit dem gleichen Festschreiben wie der Zweig beginnt feature-xyz, git cherry-pickdie Festschreibungen von feature-xyzbis feature-xyz-squashed, sie dort zusammendrücken und feature-xyz-squashednach zusammenführen master. Sie sollten dann nicht zusammenführen feature-xyz. Manchmal ist das oben Genannte sinnvoll (z. B. möchten Sie keine Commits mit einem eingeschlichenen Kennwort einfügen), aber es ist eine Problemumgehung, kaum eine bewährte Methode.
9000