本記事の内容
本記事では競合についての「補足および疑問」で記したことに対する解答である.
ただし,本記事では競合についてをすでに一読していることを前提とする.
序
以前,競合について
で競合の解決方法を述べた.
競合の解決についての結論を端的に述べるならば
- そもそも競合が起こらないようにする.
- 競合が起こってしまったら手作業で解決する.
だった.しかし,競合を解決し(git merge ブランチ名
が通し),git diff
で差分の存在が認められるのにも関わらず,その差分がマージされない場合が存在するのである.
それは一体何故なのか?ということを解決しようというのが本記事の目標である.
結論
まことに単純で,最新のコミットが最優先されるからである.
最新のコミットが最優先される,ということに対する理由は簡単である.例えば,あるブランチであるファイルを編集し,その内容をコミットしたとする.さらに,同一ファイルを同じブランチでさらに編集(アップデート)し,コミットしたとする.すると,最終的にその編集されたファイルの内容は2回目のコミットが反映された内容になっているはずである.故に,コミットは最新のものが最優先されるのである.
設定
ファイル名
mergetest.txt
というファイルの同一箇所をmasterブランチ
とtestブランチ
の2つのブランチで編集する。
各ブランチでの編集前のファイルは
i am ironman.
という1行のテキストファイルである。
競合の発生
masterブランチ
とtestブランチ
でそれぞれ次のように編集し、コミットする。
- masterブランチの内容(編集後)
i am ironman.
avengers #この行を追加。
- testブランチの内容(編集後)
i am ironman.
#2行目に空行を追加。
may the force be with you. #この行を追加。
※編集後各ブランチでコミットしておく。
この状況でgit merge master
を実行してもエラーメッセージが出力され,マージは実行されない.
競合箇所の確認
emacs mergetest.txt
を実行することで,
i am ironman.
<<<<<<< HEAD
may the force be with you.
=======
avengers
>>>>>>> master
と表示され,競合箇所を確認することができる.
マージされない差分の存在
筆者は最初,競合が発生したとき「競合箇所と思しきところをすべて削除してしまえばよいのではないか?」と思い該当箇所を削除した.すなわち,今回の例に則れば,
i am ironman.
<<<<<<< HEAD
may the force be with you.
=======
avengers
>>>>>>> master
を
i am ironman.
としたわけである。その後、git commit -m "delite something"
を実行後、再度git merge master
を行えば、masterブランチ
の内容がそのままtestブランチ
に反映されるのではないか?と思い、実行したのだが、
実行後のファイルの内容は変わらず
i am ironman.
だった。そこでgit diff master test
を実行した結果、確かに差分があることは確認できた。
これは、git merge master
も通り、かつgit diff master test
で差分が存在することが確認できてもマージがうまく実行されないということである。
より端的に言えば、最初の述べたとおり「マージされない差分が存在する」というわけである。
これはもしかしたらテキストファイルであることが問題なのか?とも思い、.py
ファイルでも実験したのだが結果は変わらずマージされない差分が存在することになった。
では、逆はどうだろうか?、すなわち、現在のi am ironman
とだけ書かれた状態でgit checkout master
を実行し、masterブランチ
へ移動後git merge test
を
実行したらどうなるだろうか?と思い実行したところ、masterブランチ
内でのファイルの内容が
i am ironman.
となった。つまり、うまくマージされたということだ。
何故マージされない差分が存在するのか?
結論で述べたとおり,最新のコミットが最優先されるからである.
競合についてに記した通り.競合を解決するための作業の本質を確認すれば.実は単純かつ明快である.
競合の解決のミソは「git側がどのバージョン(ブランチ)の内容を優先すべきか判断できないため,人間側が優先順位を判断し,望ましい形のファイルを人間が作り,コミットすることによってそのファイルが完成形であることをgit側に伝える」ことである.
つまり,今回の例においては
i am ironman.
という内容が「望ましい形のファイルである」とgit側に伝えた(コミット)したわけである.
更にいえば,このコミットが最新のコミットである.
よって,上記の内容が最新のコミットであるので,その内容が最優先される(つまり,その内容がベースになる)のだから,git diff
で差分が確認できたとしても,git merge master
を実行しても内容は変わらない.
むしろ,
i am ironman.
が望ましい形だ,ということをコミットすることによってgit側に伝えているのだからある意味内容は反映されているのである.
以上のことを踏まえると,git checkout master
し,git merge test
を行ったとき,masterブランチ
の内容が
i am ironman.
となってうまくマージされた理由もtestブランチ
の内容が最新のコミットであるため,その内容が最優先され,masterブランチ
の
avengers
部分は削除されるわけである.
結
今回は「マージされない差分が存在する」ということの理由を例とともに述べた.結論としては最初に記した通り,「最新のコミットが最優先されるから」である.
本記事の本質は,
- git側が判断できないのであれば,人間が判断して「望ましい形」のファイルを作り,コミットすることで,その内容が最優先だとgit側に伝える.
ことである.故に,今回の例においてはtestブランチ
の内容が最新で最優先されるからgit merge master
は通ってもファイルの内容は
i am ironman.
のままであり,逆に,git merge test
を実行すると
i am ironman.
avengers
から
i am ironman.
に更新されたのである.