Ich möchte einen genauen Algorithmus (oder einen ähnlichen) hinter 'git merge' kennen. Die Antworten zumindest auf diese Unterfragen sind hilfreich:
- Wie erkennt git den Kontext einer bestimmten nicht widersprüchlichen Änderung?
- Wie findet Git heraus, dass es in genau diesen Zeilen einen Konflikt gibt?
- Welche Dinge führt Git automatisch zusammen?
- Wie funktioniert git, wenn es keine gemeinsame Basis für das Zusammenführen von Zweigen gibt?
- Wie funktioniert Git, wenn es mehrere gemeinsame Grundlagen für das Zusammenführen von Zweigen gibt?
- Was passiert, wenn ich mehrere Zweige gleichzeitig zusammenführe?
- Was ist ein Unterschied zwischen Zusammenführungsstrategien?
Aber die Beschreibung eines ganzen Algorithmus wird viel besser sein.
Antworten:
Am besten suchen Sie nach einer Beschreibung eines 3-Wege-Zusammenführungsalgorithmus. Eine Beschreibung auf hoher Ebene würde ungefähr so aussehen:
B
- eine Version der Datei, die ein Vorfahr der beiden neuen Versionen (X
undY
) ist, und normalerweise die neueste dieser Basis (obwohl es Fälle gibt, in denen sie weiter zurückgehen muss, eine davon die Funktionen vongit
s Standardrecursive
Merge)X
mitB
undY
mit durchB
.Der vollständige Algorithmus befasst sich ausführlicher damit und enthält sogar einige Dokumentationen ( https://github.com/git/git/blob/master/Documentation/technical/trivial-merge.txt) sowie die
git help XXX
Seiten , wobei XXX ist einemerge-base
,merge-file
,merge
,merge-one-file
und möglicherweise einige andere). Wenn das nicht tief genug ist, gibt es immer Quellcode ...quelle
Wie funktioniert Git, wenn es mehrere gemeinsame Grundlagen für das Zusammenführen von Zweigen gibt?
Dieser Artikel war sehr hilfreich: http://codicesoftware.blogspot.com/2011/09/merge-recursive-strategy.html (hier ist Teil 2 ).
Rekursiv verwendet diff3 rekursiv, um einen virtuellen Zweig zu generieren, der als Vorfahr verwendet wird.
Z.B:
Dann:
Es gibt 2 beste gemeinsame Vorfahren (gemeinsame Vorfahren, die keine Vorfahren anderer sind)
C
undD
. Git führt sie zu einem neuen virtuellen Zweig zusammenV
und verwendet sie dannV
als Basis.Ich nehme an, Git würde einfach mit dem fortfahren, wenn es mehr gemeinsame Vorfahren gäbe, die
V
mit dem nächsten verschmelzen .Der Artikel besagt, dass Git bei einem Zusammenführungskonflikt beim Generieren des virtuellen Zweigs die Konfliktmarkierungen einfach dort belässt, wo sie sich befinden, und fortfährt.
Was passiert, wenn ich mehrere Zweige gleichzeitig zusammenführe?
Wie @Nevik Rehnel erklärte, hängt es von der Strategie ab, es wird im
man git-merge
MERGE STRATEGIES
Abschnitt gut erklärt .Nur
octopus
undours
/ odertheirs
das gleichzeitige Zusammenführen mehrerer Zweige unterstützen diesrecursive
beispielsweise nicht.octopus
weigert sich zusammenzuführen, wenn es Konflikte geben würde, undours
ist eine triviale Zusammenführung, so dass es keine Konflikte geben kann.Diese Befehle generieren ein neues Commit und haben mehr als 2 Eltern.
Ich habe eine
merge -X octopus
auf Git 1.8.5 ohne Konflikte gemacht, um zu sehen, wie es geht.Ausgangszustand:
Aktion:
Neuer Zustand:
Wie erwartet
E
hat 3 Eltern.TODO: Wie genau Octopus mit einzelnen Dateimodifikationen arbeitet. Rekursive Zwei-mal-Zwei-3-Wege-Zusammenführungen?
Wie funktioniert git, wenn es keine gemeinsame Basis für das Zusammenführen von Zweigen gibt?
@Torek erwähnt, dass die Zusammenführung seit 2.9 ohne fehlschlägt
--allow-unrelated-histories
.Ich habe es empirisch auf Git 1.8.5 ausprobiert:
a
enthält:Dann:
a
enthält:Deutung:
a\nc\n
als einzeilige Addition gelöstquelle
e379fdf34fee96cd205be83ff4e71699bdc32b18
) lehnt Git das Zusammenführen ab, wenn es keine Zusammenführungsbasis gibt, es sei denn, Sie fügen hinzu--allow-unrelated-histories
.--allow-unrelated-histories
Kann weggelassen werden, wenn zwischen den zusammengeführten Zweigen keine gemeinsamen Dateipfade vorhanden sind.ours
Zusammenführungsstrategie, aber keinetheirs
Zusammenführungsstrategie.recursive
+theirs
Strategie kann nur zwei Zweige auflösen. git-scm.com/docs/git-merge#_merge_strategiesIch bin auch interessiert. Ich weiß die Antwort nicht, aber ...
Ich denke, die Verschmelzung von git ist hochentwickelt und wird sehr schwer zu verstehen sein - aber eine Möglichkeit, dies zu erreichen, sind die Vorläufer und die Konzentration auf das Herz Ihres Anliegens. Das heißt, bei zwei Dateien, die keinen gemeinsamen Vorfahren haben, wie funktioniert Git Merge, wie sie zusammengeführt werden und wo Konflikte auftreten?
Versuchen wir, einige Vorläufer zu finden. Von
git help merge-file
:Aus Wikipedia: http://en.wikipedia.org/wiki/Git_%28software%29 -> http://en.wikipedia.org/wiki/Three-way_merge#Three-way_merge -> http: //en.wikipedia .org / wiki / Diff3 -> http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf
Dieser letzte Link ist ein PDF eines Papiers, das den
diff3
Algorithmus im Detail beschreibt. Hier ist eine Google PDF-Viewer-Version . Es ist nur 12 Seiten lang und der Algorithmus ist nur ein paar Seiten lang - aber eine umfassende mathematische Behandlung. Das mag etwas zu formal erscheinen, aber wenn Sie die Zusammenführung von git verstehen möchten, müssen Sie zuerst die einfachere Version verstehen. Ich habe es noch nicht überprüft, aber mit einem Namen wiediff3
müssen Sie wahrscheinlich auch diff verstehen (das einen längsten gemeinsamen Subsequenzalgorithmus verwendet). Es kann jedoch eine intuitivere Erklärungdiff3
geben, wenn Sie eine Google ...Jetzt habe ich gerade ein Experiment durchgeführt
diff3
undgit merge-file
. Sie nehmen die gleichen drei Eingabedateien version1 oldversion version2 und markieren Konflikte die Art und Weise gleich, mit<<<<<<< version1
,=======
,>>>>>>> version2
(diff3
auch hat||||||| oldversion
), ihr gemeinsames Erbe zeigt.Früher habe ich eine leere Datei für oldversion und nahezu identische Dateien für version1 und version2 mit nur einem zusätzlichen Zeile hinzugefügt version2 .
Ergebnis:
git merge-file
identifizierte die einzelne geänderte Zeile als Konflikt;diff3
behandelte aber die ganzen zwei Dateien als Konflikt. So ausgefeilt diff3 auch ist, die Zusammenführung von git ist selbst in diesem einfachsten Fall noch ausgefeilter.Hier sind die tatsächlichen Ergebnisse (ich habe die Antwort von @ twalberg für den Text verwendet). Beachten Sie die benötigten Optionen (siehe entsprechende Seiten).
$ git merge-file -p fun1.txt fun0.txt fun2.txt
$ diff3 -m fun1.txt fun0.txt fun2.txt
Wenn Sie wirklich daran interessiert sind, ist es ein bisschen wie ein Kaninchenbau. Für mich scheint es so tief wie reguläre Ausdrücke, der längste gängige Subsequenzalgorithmus für Diff, kontextfreie Grammatiken oder relationale Algebra. Wenn Sie dem auf den Grund gehen wollen, können Sie es meiner Meinung nach, aber es wird einige entschlossene Studien erfordern.
quelle
Hier ist die ursprüngliche Implementierung
http://git.kaarsemaker.net/git/blob/857f26d2f41e16170e48076758d974820af685ff/git-merge-recursive.py
Grundsätzlich erstellen Sie eine Liste gemeinsamer Vorfahren für zwei Commits und führen sie dann rekursiv zusammen, indem Sie sie entweder schnell weiterleiten oder virtuelle Commits erstellen, die als Grundlage für eine Drei-Wege-Zusammenführung der Dateien verwendet werden.
quelle
Wenn sich auf beiden Seiten der Zusammenführung dieselbe Zeile geändert hat, liegt ein Konflikt vor. Wenn dies nicht der Fall ist, wird die Änderung von einer Seite (falls vorhanden) akzeptiert.
Änderungen, die nicht in Konflikt stehen (siehe oben)
Nach der Definition einer Git-Merge-Basis gibt es immer nur eine (den neuesten gemeinsamen Vorfahren).
Das hängt von der Merge - Strategie (nur die
octopus
und dieours
/theirs
Strategien unterstützen Verschmelzung mehr als zwei Zweige).Dies wird in der
git merge
Manpage erklärt .quelle
git-merge-recursive
es das?git-merge-recursive
sein soll (es gibt keine Manpage und Google liefert nichts). Weitere Informationen dazu finden Sie auf den zu findengit merge
undgit merge-base
man - Seiten.git-merge
Manpage und dengit-merge-base
Manpages, auf die Sie hinweisen, werden mehrere gemeinsame Vorfahren und die rekursive Zusammenführung erläutert. Ich bin der Meinung, dass Ihre Antwort ohne eine Diskussion darüber unvollständig ist.