Git のマージコンフリクトを解決する方法


リモートのブランチやローカルのブランチをマージするときに発生せざるを得ないマー ジコンフリクトを解決する方法を紹介します.

マージコンフリクトとはそもそもあるブランチに他のブランチをマージさせる際に, 同じファイルの同じ行が競合するような場合や, 削除されたファイルを片方のブランチでは編集していた場合で発生するものです.

なのでマージコンフリクトと言っても二種類がありますので, それぞれの場合での解決方法を紹介します.

使用する Git のバージョンは 2.17.0 になります.

同じファイルの同じ行の競合

例えば master ブランチと feature ブランチの二つが存在して, それぞれのブランチで README.md というファイルを次のようにそれぞれ編集していたとします:

masterREADME.md

# Heading

This sentence is added by master branch.

featureREADME.md

# Heading

This sentence is added by feature branch.

そして master ブランチをチェックアウトしている状態で次のコマンドで feature ブランチをマージすると:

git merge feature

次のようなメッセージが表示されます:

Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

このメッセージは自動的にマージすることに失敗したので, 競合が発生した部分を手作業で直してから改めてコミットしてくださいというものです.

いわゆるマージコンフリクトが発生しましたということです.

ちゃんと Merge conflict in README.mdREADME.md で競合が発生しましたよと教えてくれています.

次のコマンドを打つと:

git status

このような情報が表示されます:

On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

マージを中止するんだったら git merge --abort でできます.

マージコンフリクトを直すことができたら git add <file> で解決したというマークをした上でコミットしてください.

そのような内容です.

なのでマージコンフリクトを手直ししてみたいと思います.

僕は Vim を使っているので次のコマンドで README.md を編集しますが, 実際にはご自身で使われているエディタで編集していただければと思います:

vim README.md

すると次のような README.md の内容が表示されます:

# Heading

<<<<<<< HEAD
This sentence is added by master branch.
=======
This sentence is added by feature branch.
>>>>>>> feature

<<<<<<< から ======= までが HEAD, つまりは master の内容を表し, ======= から >>>>>>> までが feature の内容を表します.

つまりは <<<<<<< から >>>>>>> までの間で競合が発生したということです.

なのでその部分をどうするかを編集してあげる必要があります.

master の内容のみ残し feature の内容を削除するのか, それともそれと反対のことをするのか.

もしくは新しい内容にしてしまうのか.

今回は折角なので masterfeature の内容を両方とも残したいと思います.

なので次のように編集しました:

# Heading

This sentence is added by master branch.

This sentence is added by feature branch.

お気づきになられたと思いますが, <<<<<<<, =======, >>>>>>> の行が削除されています.

これらの行はあくまで, どの行がどのブランチのものなのかを教えてくれるものなので, 最終的にマージする内容に編集することができたら, 必要ないので削除してしまいます.

これでマージコンフリクトを直すことができたので, 次のコマンドで直しましたよというマークをします:

git add README.md

そして git status を入力すると次のように情報が変化します:

On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

        modified:   README.md

全てのコンフリクトは直りました, だけどまだマージの途中ですと, All conflicts fixed but you are still merging. に書かれています.

なのでようよくコミットすることができます:

git commit

すると次のような画面が僕の場合は表示されますので:

Merge branch 'feature'

# Conflicts:
#   README.md
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
#   .git/MERGE_HEAD
# and try again.


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
#   modified:   README.md
#

僕は Vim を使っているので ZZ で確定させて, コミットを完了させます.

これでマージコンフリクトの一つ目の解決方法が終わりました.

削除したファイルと編集されたファイルの競合

お次は master ブランチの README.md は削除したけど, feature ブランチの README.md は削除することなく編集したという場合に, masterfeature をマージさせた時に発生するマージコンフリクトを解決する方法です.

masterREADME.md は削除したので存在しないですが, featureREADME.md は次のような内容になります:

# Heading

This sentence is added by feature branch.

This sentence is also added by feature branch.

このような状態で master をチェックアウトしている状態から次のコマンドを入力し masterfeature をマージさせると:

git merge feature

同じようなメッセージが表示されるかと思ったら:

CONFLICT (modify/delete): README.md deleted in HEAD and modified in feature. Version feature of README.md left in tree.
Automatic merge failed; fix conflicts and then commit the result.

ちょっとだけ内容が変わっていますね.

HEADREADME.md は削除されましたが, featureREADME.md は編集されました. なので自動的なマージは失敗しましたので, 競合を直してからコミットしてください.

という内容になってします.

git statsu を入力すると次のように表示されます:

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)

        deleted by us:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

同じように git merge --abort でマージを取り消すことができますということですね.

そして featureREADME.md を残すのであれば git add README.md を, 削除したままにするのであれば git rm README.md ということですね.

今回は削除したままにしたいと思いますので, 次のコマンドを入力するとこのように表示されます:

$ git rm README.md
README.md: needs merge
rm 'README.md'

そして git status を入力すると次のように表示されます:

On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

マージコンフリクトを解決する一つ目の方法の時と同じメッセージが表示されました.

ここまできたらあとは次のコマンドでコミットするだけですね:

git commit

すると同じように次のような内容が表示されるので:

Merge branch 'feature'

# Conflicts:
#   README.md
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
#   .git/MERGE_HEAD
# and try again.


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# All conflicts fixed but you are still merging.
#

同じように ZZ でコミットを完了させます.

これでマージコンフリクトを解決する二つ目の方法が終わりました.

まとめ

という感じでマージコンフリクトが発生した場合は, 残すものと残さないものとに分別してあげる必要があります.

でもそんなに難しい感じはしなかったのではないでしょうか.

このようにマージコンフリクトの手順自体はそんなに難しいものではないので, 重要なのは競合が発生した部分をどのように折り合いをつけて合併させることができるかということだと思います.

つまりはプログラミングのコードの問題ですね.

マージコンフリクトは Git を使う以上避けては通れないものだと思いますので, どのように解決することができるのかということを理解することに貢献できましたら幸いです.