Git merge conflict入門|競合の読み方と安全な解消手順

「Git merge conflict入門|競合の読み方と安全な解消手順」の内容を表す技術イラスト

merge conflictとは

Gitは通常、異なるbranchの変更を自動的にmergeできます。しかし、同じファイルの同じ行付近を別々のbranchで変更した場合など、Gitだけでは「どちらを最終結果として残すべきか」を安全に判断できないことがあります。この状態がmerge conflictです。

conflictはGitが壊れた状態ではありません。自動判断できない変更について、人間に最終内容を決めてもらうために処理を止めている状態です。

GitHub公式ドキュメントでも、同じ行への競合する変更や、一方で編集し他方でファイルを削除した場合などにmerge conflictが発生すると説明されています。

conflictが起きる典型例

たとえばmain branchの message.txt が次の内容だったとします。

Status: draft

feature-a branchでは次のように変更してcommitします。

Status: ready

一方、main branchでも同じ行を別の内容へ変更してcommitします。

Status: reviewed

この状態でmainからfeature-aをmergeすると、Gitには ready と reviewed のどちらを採用すべきか分かりません。そのため自動mergeを止め、解決を求めます。

逆に、別々のファイルや十分離れた行だけを変更している場合、Gitが自動mergeできることが多くあります。branchが分岐しただけで必ずconflictになるわけではありません。

まずgit statusを見る

mergeでconflictが発生したら、最初に行うことは慌ててファイルを書き換えることではありません。

git status

を実行します。

Gitは unmerged paths などとして競合中のファイルを示します。まず「どのファイルが競合しているか」を把握します。

conflict markerを読む

競合したテキストファイルには、次のようなmarkerが入ることがあります。

<<<<<<< HEAD
Status: reviewed
=======
Status: ready
>>>>>>> feature-a

基本的な意味は次の通りです。

  • <<<<<<< HEAD から ======= まで:現在checkoutしている側の内容
  • =======:二つの候補の境界
  • ======= から >>>>>>> feature-a まで:mergeしようとしている側の内容

markerは「どちらかを機械的に消せ」という命令ではありません。最終的に必要な内容を人間が判断するための比較表示です。

解消は最終形を作る作業

たとえば最終仕様として Status: ready が正しいなら、ファイルを次の状態へ編集します。

Status: ready

両方の意味を残す必要があるなら、新しい文章へ書き直しても構いません。

重要なのは、<<<<<<<、=======、>>>>>>> をすべて除去し、merge後に本当に欲しい完成状態へファイルを編集することです。

addは「解消済み」の意思表示

編集が終わったら、もう一度状態を確認します。

git status

内容が正しいことを確認したうえで、競合を解消したファイルをstageします。

git add message.txt

ここでの git add は通常のstageに加えて、「このファイルのconflictは解決した」というGitへの意思表示になります。

すべての競合を解消したら、再度確認します。

git status

問題がなければmergeを完了させます。

git commit

必要ならmessageを明示しても構いません。

git commit -m "Resolve merge conflict"

基本フローは、status → 内容を読む → 最終形へ編集 → add → status → commitです。

ours / theirsという言葉だけで判断しない

GUIやGit関連ツールでは「Accept Current」「Accept Incoming」「ours」「theirs」といった表現を見ることがあります。

便利ですが、名称だけを見て選ぶと意図しない内容を残すことがあります。merge、rebaseなど操作によって文脈も変わるため、最終ファイルの内容を読んで正しい状態を決めることを優先します。

mergeをやめたい場合

conflictを見て「今はmergeすべきではなかった」と分かった場合、無理に解消を続ける必要はありません。

通常のmerge処理中なら、次でmerge開始前の状態へ戻すことを試せます。

git merge --abort

ただし、merge開始前から未commit変更が混在していると、元の状態を完全に再構築できない場合があります。Git公式もmerge前に作業状態を整理しておくことを推奨しています。

そのため安全な習慣は、merge前に次を確認することです。

git status

作業途中の変更があるなら、内容を確認してcommitする、適切にstashする、またはmerge自体を後回しにします。

conflict解消でやってはいけないこと

conflict markerを見つけたからといって、意味を読まず片側を全部削除するのは危険です。また、markerを残したまま解消済みとしてcommitすれば、source codeや設定ファイルへmarkerそのものが残る可能性があります。

特に設定値、設計データ、schema、計算ロジックなどでは「mergeできたこと」より「最終内容が正しいこと」が重要です。必要ならtestやdiffで確認します。

git diff

stage後は次も使えます。

git diff --cached

GitHub上でのconflict解消

GitHubではPull Requestの単純なline conflictをWeb上のconflict editorで解消できる場合があります。一方、複雑なconflictはローカルcloneとcommand lineでの解消が必要です。

Web UIは変更される可能性があるため、まずcommand lineで「競合ファイルを特定し、最終内容を決め、解消済みとしてstageし、commitする」という原理を理解しておくと、VS Codeなど別のGUIでも応用できます。

まとめ

merge conflictはエラーというより、Gitが自動判断を停止した状態です。

覚えるべき基本は次の流れです。

git merge
   ↓
conflict発生
   ↓
git status
   ↓
<<<<<<< / ======= / >>>>>>> を読む
   ↓
最終的に欲しい内容へ編集
   ↓
git add
   ↓
git status
   ↓
git commit

そして解消方針に自信がなければ、無理にmergeを完成させず git merge --abort で戻る選択肢があります。

conflictを怖がらないために最も重要なのは、commandを暗記することではなく、Gitが判断できなかった二つの変更を読み、人間が正しい最終状態を決める作業だと理解することです。

参考になったらシェアしてください
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

機械設計・油圧・CAD・Python・AIなど、ものづくりに関わる技術を扱っています。工学知識を整理・構造化し、設計や自動化に再利用できる形へ変えていくことを目指しています。

目次