Git CONFLICT (content): Merge conflict の原因と解決方法

CONFLICT (content): Merge conflict in … とは

Gitで「CONFLICT (content): Merge conflict」はブランチのマージやリベース時に発生するエラーです。同じファイルの同じ箇所が異なるブランチで編集された場合、Gitが自動マージできずに発生します。チーム開発で最も日常的に遭遇するGitの問題です。

このエラーの原因は「同じファイルの同じ箇所が複数ブランチで変更された」という点です。コンフリクトマーカー(<<<<<<<)を手動で解消する必要があります。

エラーの発生パターン

このエラーは主に以下のようなケースで発生します。

パターン1: 同一行の変更によるコンフリクト

# mainブランチで greeting.txt を "Hello World" に変更
# featureブランチで greeting.txt を "Hi World" に変更
$ git merge feature
# CONFLICT (content): Merge conflict in greeting.txt
# Automatic merge failed; fix conflicts and then commit the result.

同じファイルの同じ行が異なるブランチで変更されたため、Gitが自動マージできずコンフリクトが発生します。ファイルにはコンフリクトマーカーが挿入され、手動で解決する必要があります。

# コンフリクトマーカーの意味:
# <<<<<<< HEAD         ← 現在のブランチ(main)の変更
# Hello World
# =======              ← 区切り線
# Hi World
# >>>>>>> feature      ← マージ元ブランチ(feature)の変更

# 手動で正しい内容に編集後:
$ git add greeting.txt
$ git commit -m "Merge feature branch: resolve conflict in greeting.txt"

パターン2: rebase時のコンフリクト

$ git rebase main
# CONFLICT (content): Merge conflict in app.js
# error: could not apply abc1234... Update app logic
# hint: Resolve all conflicts manually, mark them as resolved with
# hint: "git add" and run "git rebase --continue".

rebaseはコミットを1つずつ再適用するため、複数のコミットでコンフリクトが連続して発生する場合があります。

# rebaseのコンフリクト解決手順
$ git status  # コンフリクトファイルを確認
# コンフリクトを手動解決
$ git add app.js
$ git rebase --continue

# rebaseを中止したい場合
$ git rebase --abort

パターン3: 削除と編集のコンフリクト

# mainブランチで config.yml を削除
# featureブランチで config.yml を編集
$ git merge feature
# CONFLICT (modify/delete): config.yml deleted in HEAD and modified in feature.

一方のブランチでファイルを削除し、もう一方で同じファイルを編集した場合に発生します。ファイルを残すか削除するかを手動で判断する必要があります。

# ファイルを残す場合
$ git add config.yml
$ git commit

# ファイルを削除する場合
$ git rm config.yml
$ git commit
VSCode、IntelliJ IDEA、GitKrakenなどのGUIツールにはコンフリクト解決を支援する機能があります。コンフリクトマーカーをビジュアルに表示し、「Accept Current」「Accept Incoming」「Accept Both」などのボタンで簡単に解決できます。

根本原因の特定方法

git statusでコンフリクトしているファイルの一覧を確認します。各ファイルを開き、コンフリクトマーカー(<<<<<<<、=======、>>>>>>>)の箇所を探します。どちらの変更を採用するか、または両方を統合するかを判断して手動で編集します。

# コンフリクトの状態確認
$ git status
# both modified: app.js

# コンフリクトマーカーを検索
$ grep -n '<<<<<<' app.js

# マージの差分を確認
$ git diff

# マージ元とマージ先のそれぞれの変更を確認
$ git diff --ours app.js    # 現在ブランチの変更
$ git diff --theirs app.js  # マージ元の変更

防止策とベストプラクティス

コンフリクトを減らすには、ブランチの寿命を短く保ち、こまめにmainブランチの変更を取り込むことが重要です。また、チーム内でファイルの担当範囲を明確にし、同じファイルの同時編集を避ける運用も効果的です。

# コンフリクト防止のベストプラクティス
# 1. こまめにmainの変更を取り込む
$ git fetch origin
$ git rebase origin/main

# 2. 作業ブランチを短命に
$ git checkout -b feature/small-change
# ... 小さな変更 ...
$ git push && プルリクエスト作成

# 3. マージ前にリモートの最新を確認
$ git pull origin main --rebase
ブランチの寿命を短くし、こまめにmainを取り込むことが、コンフリクト防止の最も効果的な方法です。大きな機能開発はフィーチャーフラグを活用して小分けにマージしましょう。

Stack Overflowでの質問状況

Stack Overflowでは、Bashに関する質問が約154,252件投稿されており、CONFLICT (content): Merge conflict in …は最も頻繁に質問されるエラーカテゴリの一つです。

よくある質問(FAQ)

Q
マージとリベースのコンフリクト解決の違いは?
A

マージはコンフリクトを1回で解決しますが、リベースはコミットごとに解決する必要があるため、複数回コンフリクトが発生する場合があります。リベースはコミット履歴がきれいになる一方、解決の手間は増える可能性があります。

Q
コンフリクト解決を間違えた場合は元に戻せますか?
A

マージの場合はgit merge –abortで中断できます。すでにコミットした場合はgit revertで取り消せます。リベースの場合はgit rebase –abortで中断するか、git reflogで以前の状態に戻すことが可能です。

Q
コンフリクトを自動解決する方法はありますか?
A

git merge -X ours(現在ブランチ優先)やgit merge -X theirs(マージ元優先)で自動解決できますが、意図しない変更の消失リスクがあるため注意が必要です。通常は手動解決が推奨されます。

免責事項: 当記事の情報は執筆時点の内容に基づいています。最新情報は各公式サイトをご確認ください。当サイトは情報提供を目的としており、資格取得・技術的対応の結果について一切の責任を負いません。

コメント

タイトルとURLをコピーしました