Yo también estoy interesado. No sé la respuesta, pero ...
Un sistema complejo que funciona invariablemente ha evolucionado a partir de un sistema simple que funcionó
Creo que la fusión de git es muy sofisticada y será muy difícil de entender, pero una forma de abordar esto es a partir de sus precursores y centrarse en el corazón de su preocupación. Es decir, dados dos archivos que no tienen un ancestro común, ¿cómo resuelve git merge cómo fusionarlos y dónde están los conflictos?
Intentemos encontrar algunos precursores. De git help merge-file
:
git merge-file is designed to be a minimal clone of RCS merge; that is,
it implements all of RCS merge's functionality which is needed by
git(1).
De 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
Ese último enlace es un pdf de un artículo que describe el diff3
algoritmo en detalle. Aquí hay una versión del visor de pdf de Google . Tiene solo 12 páginas y el algoritmo tiene solo un par de páginas, pero un tratamiento matemático completo. Eso puede parecer un poco demasiado formal, pero si desea comprender la fusión de git, primero deberá comprender la versión más simple. Aún no lo he comprobado, pero con un nombre como diff3
, probablemente también necesitará comprender diff (que usa un algoritmo de subsecuencia común más largo ). Sin embargo, puede haber una explicación más intuitiva de diff3
ahí fuera, si tiene un google ...
Ahora, acabo de hacer un experimento comparando diff3
y git merge-file
. Se llevan a los mismos tres archivos de entrada version1 OldVersion version2 y conflictos marcan el camino mismo, con <<<<<<< version1
, =======
, >>>>>>> version2
( diff3
también tiene ||||||| oldversion
), mostrando su patrimonio común.
He utilizado un archivo vacío para OldVersion y archivos casi idénticos para version1 y version2 con una sola línea extra añadido a version2 .
Resultado: git merge-file
identificó la única línea modificada como el conflicto; pero diff3
trató los dos archivos completos como un conflicto. Por lo tanto, por más sofisticada que sea diff3, la fusión de git es aún más sofisticada, incluso para el caso más simple.
Aquí están los resultados reales (utilicé la respuesta de @ twalberg para el texto). Tenga en cuenta las opciones necesarias (consulte las páginas de manual correspondientes).
$ git merge-file -p fun1.txt fun0.txt fun2.txt
You might be best off looking for a description of a 3-way merge algorithm. A
high-level description would go something like this:
Find a suitable merge base B - a version of the file that is an ancestor of
both of the new versions (X and Y), and usually the most recent such base
(although there are cases where it will have to go back further, which is one
of the features of gits default recursive merge) Perform diffs of X with B and
Y with B. Walk through the change blocks identified in the two diffs. If both
sides introduce the same change in the same spot, accept either one; if one
introduces a change and the other leaves that region alone, introduce the
change in the final; if both introduce changes in a spot, but they don't match,
mark a conflict to be resolved manually.
<<<<<<< fun1.txt
=======
THIS IS A BIT DIFFERENT
>>>>>>> fun2.txt
The full algorithm deals with this in a lot more detail, and even has some
documentation (/usr/share/doc/git-doc/technical/trivial-merge.txt for one,
along with the git help XXX pages, where XXX is one of merge-base, merge-file,
merge, merge-one-file and possibly a few others). If that's not deep enough,
there's always source code...
$ diff3 -m fun1.txt fun0.txt fun2.txt
<<<<<<< fun1.txt
You might be best off looking for a description of a 3-way merge algorithm. A
high-level description would go something like this:
Find a suitable merge base B - a version of the file that is an ancestor of
both of the new versions (X and Y), and usually the most recent such base
(although there are cases where it will have to go back further, which is one
of the features of gits default recursive merge) Perform diffs of X with B and
Y with B. Walk through the change blocks identified in the two diffs. If both
sides introduce the same change in the same spot, accept either one; if one
introduces a change and the other leaves that region alone, introduce the
change in the final; if both introduce changes in a spot, but they don't match,
mark a conflict to be resolved manually.
The full algorithm deals with this in a lot more detail, and even has some
documentation (/usr/share/doc/git-doc/technical/trivial-merge.txt for one,
along with the git help XXX pages, where XXX is one of merge-base, merge-file,
merge, merge-one-file and possibly a few others). If that's not deep enough,
there's always source code...
||||||| fun0.txt
=======
You might be best off looking for a description of a 3-way merge algorithm. A
high-level description would go something like this:
Find a suitable merge base B - a version of the file that is an ancestor of
both of the new versions (X and Y), and usually the most recent such base
(although there are cases where it will have to go back further, which is one
of the features of gits default recursive merge) Perform diffs of X with B and
Y with B. Walk through the change blocks identified in the two diffs. If both
sides introduce the same change in the same spot, accept either one; if one
introduces a change and the other leaves that region alone, introduce the
change in the final; if both introduce changes in a spot, but they don't match,
mark a conflict to be resolved manually.
THIS IS A BIT DIFFERENT
The full algorithm deals with this in a lot more detail, and even has some
documentation (/usr/share/doc/git-doc/technical/trivial-merge.txt for one,
along with the git help XXX pages, where XXX is one of merge-base, merge-file,
merge, merge-one-file and possibly a few others). If that's not deep enough,
there's always source code...
>>>>>>> fun2.txt
Si está realmente interesado en esto, es una especie de madriguera. Para mí, parece tan profundo como las expresiones regulares, el algoritmo de subsecuencia común más largo de diff, gramáticas libres de contexto o álgebra relacional. Si quiere llegar al fondo, creo que puede, pero requerirá un estudio decidido.