Também estou interessado. Não sei a resposta, mas ...
Um sistema complexo que funciona invariavelmente evoluiu a partir de um sistema simples que funcionou
Acho que a fusão do git é altamente sofisticada e será muito difícil de entender - mas uma maneira de abordar isso é partindo de seus precursores e focar no centro de sua preocupação. Ou seja, dados dois arquivos que não têm um ancestral comum, como git merge funciona como mesclá-los e onde estão os conflitos?
Vamos tentar encontrar alguns 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).
Da 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
O último link é um pdf de um artigo que descreve o diff3
algoritmo em detalhes. Aqui está uma versão do visualizador de pdf do google . Tem apenas 12 páginas, e o algoritmo tem apenas algumas páginas - mas um tratamento matemático completo. Isso pode parecer um pouco formal, mas se você quiser entender o merge do git, você precisará entender a versão mais simples primeiro. Eu não verifiquei ainda, mas com um nome como diff3
, você provavelmente também precisará entender diff (que usa um algoritmo de subsequência comum mais longo ). No entanto, pode haver uma explicação mais intuitiva do que está diff3
por aí, se você tiver um google ...
Agora, acabei de fazer uma experiência comparando diff3
e git merge-file
. Eles tomam os mesmos três arquivos de entrada version1 OldVersion version2 e conflitos marcam o caminho mesma, com <<<<<<< version1
, =======
, >>>>>>> version2
( diff3
também tem ||||||| oldversion
), mostrando o seu património comum.
Eu usei um arquivo vazio para OldVersion e arquivos quase idênticas para version1 e version2 com apenas uma linha extra adicionado ao version2 .
Resultado: git merge-file
identificou a única linha alterada como o conflito; mas diff3
tratou os dois arquivos inteiros como um conflito. Portanto, por mais sofisticado que o diff3 seja, o merge do git é ainda mais sofisticado, mesmo para os casos mais simples.
Aqui estão os resultados reais (usei a resposta de @twalberg para o texto). Observe as opções necessárias (consulte as respectivas páginas de manual).
$ 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
Se você estiver realmente interessado nisso, é uma espécie de toca de coelho. Para mim, parece tão profundo quanto expressões regulares, o algoritmo de subsequência comum mais longo de diff, gramáticas livres de contexto ou álgebra relacional. Se você quiser chegar ao fundo disso, acho que pode, mas vai exigir um estudo determinado.