質問: 以下のような事例について質問です --- ・masterのコミット A - B - C - D ・topicのコミット A - B - E - F topicをmasterへマージするためにPullRequestを送ろうとしたところ、Github上でコンフリクトが発生していることがわかりました。 masterへマージする権限がないため、topicブランチにmasterをマージし、コンフリクトを解決させました。 ・topicのコミット A - B - E - F - C - D - G (Gはマージコミット) Github上でコンフリクトは無いと判定され、無事マージすることができました。 --- このとき、topicでmasterをマージし、コンフリクトを解決したコミット G にはどのような情報が含まれているのでしょうか? 私の予想では「masterのコミットDまでの競合を解決した」といった情報が保存されているのかなと推測しています。
回答: こんにちは。 gitの内部の話をします。 gitのコミットは、「差分情報」を一切保持していません。もう少し具体的に言うと、コミットオブジェクトは、コミッター名、作成日時、コミットメッセージ、コミット時のインデックスツリーオブジェクトへの参照(ツリーオブジェクトは各ファイルオブジェクトへの参照を持ちます)、そして、親コミットのID、を固めたものです。gitそれ自体はとてもシンプルなオブジェクトツリーデータベースであり、コミットの差分情報というのは「画面に表示する時に」自分のツリーのファイルと親コミットの持つツリーのファイル同士を比較して作成されているのです。 よって、マージコミットが持つのは「コミットの各種メタデータ」、「マージコミット時点のインデックスツリーへの参照」「二つ(以上)の親コミットのID」となります。 仮にマージする段階でコンフリクトを解消する編集を加えたとして、それは「編集された後のファイル」がインデックスツリーに含まれるだけなので、マージがどのようにコンフリクトして、どのように解消したかという情報は失われます。「マージする前の二つのインデックス(ディレクトリ)の状態」と、「マージが完了した時点のインデックスの状態」があれば、バージョン管理には十分なのです。 githubでコミットログを表示すると、マージ含め直線的に表示されてしまいますが、マージは実際にはツリー構造になっています。ローカルでCUIから`git log --graph`や、またはSourceTreeなどを使うと視覚化できるので、理解の助けになると思います。