スポンサーリンク

マージされない差分が存在する【GitHubシリーズ】その7

本記事の内容

本記事では競合についての「補足および疑問」で記したことに対する解答である.

ただし,本記事では競合についてをすでに一読していることを前提とする.

以前,競合について
で競合の解決方法を述べた.
競合の解決についての結論を端的に述べるならば

  • そもそも競合が起こらないようにする.
  • 競合が起こってしまったら手作業で解決する.

だった.しかし,競合を解決し(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.

に更新されたのである.

ページの先頭に戻る