Anche a me interessa. Non so la risposta, ma ...
Si scopre invariabilmente che un sistema complesso che funziona si è evoluto da un sistema semplice che funzionava
Penso che l'unione di git sia altamente sofisticata e sarà molto difficile da capire, ma un modo per avvicinarsi a questo è dai suoi precursori e concentrarsi sul cuore della tua preoccupazione. Cioè, dati due file che non hanno un antenato comune, come funziona git merge come unirli e dove sono i conflitti?
Proviamo a trovare alcuni precursori. Da 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
Quest'ultimo collegamento è un pdf di un documento che descrive diff3
in dettaglio l' algoritmo. Ecco una versione del visualizzatore di pdf di Google . È lungo solo 12 pagine e l'algoritmo è solo un paio di pagine, ma un trattamento matematico completo. Potrebbe sembrare un po 'troppo formale, ma se vuoi capire l'unione di git, dovrai prima capire la versione più semplice. Non ho ancora controllato, ma con un nome come diff3
, probabilmente dovrai anche capire diff (che utilizza un algoritmo di sottosequenza comune più lungo ). Tuttavia, potrebbe esserci una spiegazione più intuitiva diff3
là fuori, se hai un google ...
Ora, ho appena fatto un esperimento confrontando diff3
e git merge-file
. Prendono le stesse tre file di input version1 oldversion version2 e conflitti segnare la strada stessa, con <<<<<<< version1
, =======
, >>>>>>> version2
( diff3
ha anche ||||||| oldversion
), mostrando il loro patrimonio comune.
Ho usato un file vuoto per oldversion e file quasi identici per version1 e version2 con solo una riga in più aggiunta a version2 .
Risultato: git merge-file
identificato la singola riga modificata come conflitto; ma ha diff3
trattato i due file interi come un conflitto. Così, sofisticato come diff3, l'unione di git è ancora più sofisticata, anche per questo dei casi più semplici.
Ecco i risultati effettivi (ho usato la risposta di @ twalberg per il testo). Annotare le opzioni necessarie (vedere le rispettive manpage).
$ 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 sei veramente interessato a questo, è un po 'una tana di coniglio. A me sembra profondo quanto le espressioni regolari, l' algoritmo di sottosequenza comune più lungo di diff, grammatiche libere dal contesto o algebra relazionale. Se vuoi andare fino in fondo, penso che tu possa farlo, ma ci vorrà uno studio determinato.