Gitコンフリクト解消ガイド(git mergetoolの使い方)

  • 784
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

ファイル編集がコンフリクトした場合

下記はよくある(忌々しい)コンフリクト画面ですね。

コンフリクトしたときのgit status

皆さんはコンフリクトのmergeはどんな方法でやっていますでしょうか?
vimやemacsで直接編集している方が多いイメージですが、実際開いてみると、下記のように差分が表示されていると思います。

conflict-marker.png

この画面を見ただけではどのようにmergeすればよいのかわかりません。(Objective-CのARC/MRC双方の開発経験がある人は目をつぶってください・・)

gitにはこのようなコンフリクトのmergeを支援するgit mergetoolコマンドが搭載されています。

git mergetoolのプロンプト

このままEnterキーを押すと下記のような画面が立ち上がります。

mergetool2.png

画面幅の都合でフォントが小さいのですが、ここで「mergeしたい差分が作られる直前の状態」と「mergeしたい差分」に注目してみます。

mergetool2-base-remote.png

この2つを見比べると、@propertyの「*adapter」のところが「*webViewAdapter」に変更になっていることがわかります。
mergeしたい差分の内容は実際には上記の変数名の変更だったのです。

ですので、「merge結果として保存するファイル」の中でコンフリクトした箇所の上側(画面内だとHEAD側)で、adapterをwebViewAdapterに書きかえます。下側とコンフリクトマーカは忘れずに削除しましょう。

ちなみに、git mergeでコンフリクトした場合は、真ん中はbranchが枝分かれした時の状態で、左は現在のbranchに追加された差分、右はmergeしたいbranchに追加された差分ということになります(3-way merge)。
ですので、真ん中と左を比べると、現在のbranchがどのように進んだのかを確認することができます。
今回は、ARC対応でretainがstrongに、assignがweakになったことがわかります。

merge後の状態

mergeが完了したら、保存してエディタを終了します。merge前の状態は、該当のファイル.origとして保存されます。自動的にgit addされているので、コミットしましょう。

※なお、キャンセルする場合は1回も保存をせずにエディタを終了します。

※ちなみに現状ではvimのみの対応となります・・emacsでも設定方法があるようなので、うまく言った方はよければコメント等ください。

(Xcode用の)GUIのdiffツールっぽいのが起動する場合

opendiffになっている人がちょくちょくいるみたいなので、下記のコマンドでvimdiffに切り替えてください。

git config --global merge.tool vimdiff

(番外編)mergetoolを使わず似た方法でmergeする

宗教上の都合でvimが使えない方や画面が狭い方に朗報です。

通常のコンフリクトマーカだとmergetoolの真ん中の画面(mergeしたい差分が作られる直前の状態、BASE)が欠落していましたが、コンフリクトマーカにそれを表示するオプションがありました。

git config --global merge.conflictstyle diff3

コンフリクトマーカが下記のようになります。

<<<<<<< HEAD
merge前の状態
||||||| merged common ancestors
mergeしたい差分が作られる直前の状態
=======
mergeしたい差分
>>>>>>> branch

とりあえず設定しておいても損はしません。mergetool使うほどでかいconflictじゃないときにも重宝します。
※ただし、コンフリクトしていない場所に加えられた変更を把握できないので、大きい差分にはmergetoolを使うか、git diffを組み合わせて使うほうが良さそうです。

参照: http://qiita.com/hchbaw/items/1191c2627307a4673b1b

ファイル削除がコンフリクトした場合(path conflict)

削除したファイルが編集されていた時に起きます。

  • Deleted by them:
    • mergeする差分で削除されています
    • 現在のbranchで変更されています
  • Deleted by us:
    • 現在のbranchで削除されています
    • mergeする差分で変更されています

多くの場合最終的に削除を採用することになると思いますが、mergeのためにファイルが残されているので、下記のようにします。

git rm path/to/target/file

※unmergedっぽいメッセージが出ますが、きちんと削除が反映されます。

同じ差分を複数回mergeする場合

gitにはコンフリクトした差分のmerge結果を保存しておき再利用するrerere機能というものがあります。
メンテナとかリリース担当で、同じ差分で複数回mergeする場合に便利です。
下記のコマンドで有効にできます。

git config --global rerere.enabled true

http://d.hatena.ne.jp/unpush/20091010/1255186302