残念なことに、多くのマージは自明ではありませんん。 追加や移動、削除されたファイルがある場合や、あるいは両方のブランチ で同じファイルが変更されている場合、"マージエントリ" を含んだ 索引ツリーが残されます。このような索引ツリーは tree オブジェクトには書き込むことができません。その結果を書き込む前に 他のツールを使用してコンフリクトを解消する必要があります。
このような索引状態は git ls-files —unmerged
を
用いると確認できます。例えば:
$ git read-tree -m $orig HEAD $target
$ git ls-files --unmerged
100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello.c
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello.c
100644 cc44c73eb783565da5831b4d820c962954019b69 3 hello.c
git ls-files —unmerged
の出力の各行は blob のモードビット、
blob の SHA-1、stage番号'、そしてファイル番号で始まります。
'stage番号 はそれがどの tree から来たかを表す git のやり方です:
stage 1 は $orig
ツリーに対応し、stege 2 は HEAD
の tree
stage 3 $target
tree です。
既に自明のマージは git read-tree -m
にて行なわれたことを
説明しました。例えば、ファイルが HEAD と
$target` のどちらでも
変更されていない場合や、HEAD
と $target
が同じ内容の場合は
明らかに最終的な結果は HEAD
のものと同じです。
上記の例では hello.c
は HEAD
で変更されていて $target`でも
別の変更が行なわれている場合です。
好きな3方向マージツールを実行してこれを解決することができます。
例えば `diff3`、`merge
あるいは git 自身の merge-file などを使用し
これら3つのstage 上のファイルを次のようにしてマージします。
$ git cat-file blob 263414f... >hello.c~1
$ git cat-file blob 06fa6a2... >hello.c~2
$ git cat-file blob cc44c73... >hello.c~3
$ git merge-file hello.c~2 hello.c~1 hello.c~3
これはマージ結果は hello.c~2
ファイルに保存し、
コンフリクトがあるときは、コンフリクトマーカが付けられます。
マージ結果を確認した後、このファイルの最終的なマージ結果を
git に次のようにして伝えます:
$ mv -f hello.c~2 hello.c
$ git update-index hello.c
ファイルにマージ済みになっていない時は、git update-index
は
ファイルに解決済みのマークを付けます。
上記は下位レベルにおける git のマージ動作の解説で、
水面下でどのようなことが起きているかの概念を理解する手助けになります。
実際、誰も、git 自身でさえ、git cat-file
を3回も実行しません。
git merge-index
プログラムがあり、これが stage を一時ファイルとして
抽出し、"merge" スクリプトをコールします:
$ git merge-index git-merge-one-file hello.c
そして、上位レベルとして git merge -s resolve
が実装されています。