私も興味があります。答えはわかりませんが...
動作する複雑なシステムは、動作する単純なシステムから常に進化していることがわかります
gitのマージは非常に洗練されており、理解するのは非常に難しいと思いますが、これにアプローチする1つの方法は、その前身から、懸念の中心に焦点を当てることです。つまり、共通の祖先を持たない2つのファイルがある場合、git mergeはそれらをマージする方法と、競合がどこにあるかをどのように計算しますか?
いくつかの前駆体を見つけてみましょう。差出人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).
ウィキペディアから: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
その最後のリンクは、diff3
アルゴリズムを詳細に説明している論文のpdfです。これがグーグルのPDFビューアーバージョンです。長さはわずか12ページで、アルゴリズムはわずか数ページですが、完全な数学的処理です。それは少し形式的すぎるように思えるかもしれませんが、gitのマージを理解したい場合は、最初に単純なバージョンを理解する必要があります。まだ確認していませんが、のような名前の場合diff3
、おそらくdiff(最長共通部分列アルゴリズムを使用)も理解する必要があります。しかし、diff3
あなたがグーグルを持っているなら、そこにもっと直感的な説明があるかもしれません...
今、私はちょうど、比較実験を行ったdiff3
とgit merge-file
。彼らは、同じ3つの入力ファイル取るVERSION1 oldversion VERSION2で、マークの競合方法は同じ<<<<<<< version1
、=======
、>>>>>>> version2
(diff3
も持っている||||||| oldversion
)、彼らの共通の遺産を示します。
oldversionには空のファイルを使用し、version1とversion2にはほぼ同じファイルを使用し、version2に1行だけ追加しました。
結果:git merge-file
変更された単一の行が競合として識別されました。しかしdiff3
、2つのファイル全体を競合として扱いました。したがって、diff3のように洗練されているので、この最も単純なケースでも、gitのマージはさらに洗練されています。
これが実際の結果です(テキストには@twalbergの回答を使用しました)。必要なオプションに注意してください(それぞれのマンページを参照)。
$ 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
あなたが本当にこれに興味があるなら、それはちょっとしたうさぎの穴です。私には、正規表現、diffの最長共通部分列アルゴリズム、文脈自由文法、または関係代数と同じくらい深いように見えます。根底に行きたいのならできると思いますが、ある程度の検討が必要です。