CONFLICT と表示されて手が止まった人に向けて書きます。ファイルに見慣れない記号が入り、何かを壊したように見えますが、壊れてはいません。この記事では、料金表の同じ行を2人が変えた場面を実際に動かし、表示の読み方、直し方、やめ方を順に追います。GitHubの画面とVS Codeでの直し方も扱います。読み終わると、次に同じ表示が出ても自分で判断できます。
この記事の内容
先に答えると
コンフリクトは、同じファイルの同じ場所を2人が別々に変えたため、どちらを残すかをGitが決められない状態です。データは失われていません。Gitが手を止めて、人に判断を求めているだけです。
- 直し方は3段階です。ファイルの
<<<<<<<、=======、>>>>>>>を消して正しい内容にする、git add、git commit - やめたいときは
git merge --abortで合流前に戻せます - GitHubの画面でも「Resolve conflicts」で直せます。単純な行の競合に限ります
- AIに任せたら、どちらを残したかを差分で必ず確かめます
- Excelや画像は行単位で混ぜられません。どちらか一方を選ぶことになります
コンフリクトは「機械が決められない」という知らせです
Gitは2つの枝を合流させるとき、枝が分かれた時点の内容と、両方の枝の内容を比べます。片方しか変えていない場所は、変えたほうを自動で採用します。両方が同じ場所を変えていると、どちらが正しいかはGitには分かりません。
サンプル料理教室の料金表で考えます。外注エンジニアBが和食の基本を6,500円に直し、代表は同じ行を6,200円に直しました。どちらが正しいかは料金を決めた人にしか分かりません。ここで勝手に片方を選ばないのがGitの仕事です。
ブランチ(枝)は本筋から分かれて作業する線、マージは枝を合流させることです。本筋の枝を main と呼びます。コンフリクトが起きるのは主にマージのときで(git pull、枝を付け直す rebase、打ち消しの revert でも起きます)、枝の作業中や保存中には起きません。

起きる条件と、起きない例
実際に動かして確かめた結果です。
| 2人がしたこと | 結果 |
|---|---|
| 別のファイルを変えた | 起きない |
| 同じファイルの離れた行を変えた | 起きない |
| 同じファイルの同じ行を変えた | 起きる |
| 同じファイルの隣り合った行を変えた | 起きる |
| 片方が変更し、もう片方が同じファイルを消した | 起きる |
| Excelや画像を両方が変えた | 起きる |
和食の料金と問い合わせの電話番号のように離れた行なら、自動で合流します。
$ git merge --no-edit fix-phone
Auto-merging menu.html
Merge made by the 'ort' strategy.
menu.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
意外なのは隣り合った行です。和食と洋食は別の講座で別の行なのに、並んでいるだけで止まります。
$ git merge fix-neighbor
Auto-merging menu.html
CONFLICT (content): Merge conflict in menu.html
Automatic merge failed; fix conflicts and then commit the result.
逆に、コンフリクトが出なくても内容が正しいとは限りません。代表が menu.html の料金を変え、Bが index.html に古い料金を書いても、別のファイルなのでGitは止まりません。Gitが見ているのは文字の位置だけで、意味は見ていません。
動かして再現する
ここからは本題の場面を、そのままの順で動かします。
2人が同じ行を変える
Bは枝を作って和食の基本を6,500円に変え、pushします。pushはGitHubに送る操作です。この記事では練習用の場所に送っているので、To の行が ../website.git になっています。
$ git switch -c fix-menu-price
Switched to a new branch 'fix-menu-price'
$ git add menu.html
$ git commit -m "和食の基本を6,500円に修正"
[fix-menu-price 7a1962f] 和食の基本を6,500円に修正
1 file changed, 1 insertion(+), 1 deletion(-)
$ git push -u origin fix-menu-price
To ../website.git
* [new branch] fix-menu-price -> fix-menu-price
branch 'fix-menu-price' set up to track 'origin/fix-menu-price'.
同じころ、代表は main で同じ行の名前と金額を変えました。履歴は次のように分かれています。
$ git log --oneline --graph --all
* 3215a2a 和食の基本の名前と料金を修正
| * 7a1962f 和食の基本を6,500円に修正
|/
* 4ccaca6 最初の版
合流すると CONFLICT と出る
代表が main にBの枝を合流させます。
$ git merge origin/fix-menu-price
Auto-merging menu.html
CONFLICT (content): Merge conflict in menu.html
Automatic merge failed; fix conflicts and then commit the result.
「menu.html で競合したので、直してからコミットしてください」という意味です。Gitはここで止まり、合流の記録はまだ作っていません。git status で状況を見ます。
$ git status
On branch main
Your branch is up to date with 'origin/main'.
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: menu.html
no changes added to commit (use "git add" and/or "git commit -a")
both modified が「両方が変えた」ファイルです。ファイルが多いときも、ここに出たものだけ直せば足ります。
ファイルの中の記号を読む
menu.html を開くと、競合した場所に記号が入っています。
$ cat menu.html
<h1>料金表</h1>
<table>
<<<<<<< HEAD
<tr><td>和食の基本(全4回)</td><td>6,200円</td></tr>
=======
<tr><td>和食の基本</td><td>6,500円</td></tr>
>>>>>>> origin/fix-menu-price
<tr><td>家庭の洋食</td><td>6,500円</td></tr>
<tr><td>親子パン教室</td><td>4,800円</td></tr>
<tr><td>季節の和菓子</td><td>5,200円</td></tr>
<tr><td>魚のさばき方</td><td>6,800円</td></tr>
</table>
<p>お問い合わせ: 03-0000-0000</p>
| 記号 | 意味 | この例 |
|---|---|---|
<<<<<<< HEAD | ここから今いる枝の内容 | main にいる代表の版 |
======= | 2つの版の区切り | ここより上が代表、下がB |
>>>>>>> origin/fix-menu-price | ここまでが入ってくる枝の内容 | Bの版 |
競合していない行はそのままです。洋食や電話番号の行は触らなくて構いません。

直して add、commit する
直すとは、3つの記号を消して、残すべき内容だけにすることです。片方を選ぶとは限りません。この場面では、Bに確認して、名前は代表の「全4回」、金額はBの6,500円が正しいと分かったので、両方を生かした1行にします。
$ grep -n 和食 menu.html
3:<tr><td>和食の基本(全4回)</td><td>6,500円</td></tr>
保存したら git add で「直しました」とGitに伝えます。
$ git add menu.html
$ git status
On branch main
Your branch is up to date with 'origin/main'.
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: menu.html
git commit を実行すると、既定のメッセージが入った編集画面が開きます。そのまま保存して閉じれば合流の記録ができます。ここまで終えると main の履歴は合流した形になり、git push で送れます。
$ git commit
[main 8d63472] Merge remote-tracking branch 'origin/fix-menu-price'
$ git log --oneline --graph -5
* 8d63472 Merge remote-tracking branch 'origin/fix-menu-price'
|\
| * 7a1962f 和食の基本を6,500円に修正
* | 3215a2a 和食の基本の名前と料金を修正
|/
* 4ccaca6 最初の版
$ git push
To ../website.git
3215a2a..8d63472 main -> main
記号の間に元の内容も出す
3つの記号だけだと、もともと何だったかが見えません。リポジトリに merge.conflictStyle の設定を入れると、||||||| の下に分かれる前の内容が出ます。入れなくても直せますが、判断に迷うことが多いなら役に立ちます。
$ git config --local merge.conflictStyle diff3
この設定で親子パン教室の行を競合させると、該当の部分は次のように出ます。
<<<<<<< HEAD
<tr><td>親子パン教室</td><td>5,000円</td></tr>
||||||| 8d63472
<tr><td>親子パン教室</td><td>4,800円</td></tr>
=======
<tr><td>親子パン教室</td><td>4,900円</td></tr>
>>>>>>> a1
やめて元に戻す
判断がつかない、Bに聞いてからにしたいというときは、やめて構いません。git merge --abort で合流を始める前に戻ります。
$ git merge --abort
$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
$ grep -n 和食 menu.html
3:<tr><td>和食の基本(全4回)</td><td>6,200円</td></tr>
記号が消え、代表の版に戻りました。Bの枝もそのまま残っているので、いつでもやり直せます。合流が始まっていないときに実行すると fatal: There is no merge to abort (MERGE_HEAD missing). と出ますが、これは「やめるものがない」という知らせで、害はありません。
注意が1つあります。コミットしていない変更がある状態で合流を始めると、--abort で元に戻せないことがあると公式に書かれています。git merge の前にコミットを済ませておきます。
GitHubの画面で解消する
プルリクエスト(Pull Request、PR)で競合していると、「Merge pull request」のボタンが押せなくなります。プルリクエストは、枝を本筋に入れていいかを確認する依頼のことです。単純な行の競合なら、次の手順で画面の中で直せます。
- プルリクエストの下のほうにある「Resolve conflicts」を押す
- 編集画面で内容を直し、
<<<<<<<、=======、>>>>>>>を消す - 「Mark as resolved」を押す
- 他に競合したファイルがあれば左の一覧から選び、同じように直す
- 「Commit merge」を押す
- 確認が出たら「Create branch and update my pull request」か「I understand, continue updating」で始まるボタンを選ぶ
- プルリクエストの画面に戻り、「Merge pull request」を押す
ここで起きていることは手元の操作と少し違います。Commit merge で変わるのは main ではなくBの枝です。main の内容全部をBの枝に合流させて、そこで競合を片付けています。main が変わるのは7の時点です。
「Resolve conflicts」が押せないときは、ファイルの削除と変更がぶつかった場合など、画面で扱えない競合です。手元のコマンドで直します。保護された枝がからむ場合は、新しい枝を作るよう求められます。

VS Codeで解消する
VS Codeはコードを編集するためのエディタで、Gitの競合を画面で直せます。競合したファイルを開くと、該当箇所の上に次の4つの文字が出ます。
| 表示 | していること | この例で押すと |
|---|---|---|
| Accept Current Change | 今いる枝の版を残す | 代表の6,200円になる |
| Accept Incoming Change | 入ってくる枝の版を残す | Bの6,500円になる |
| Accept Both Changes | 両方残す | 和食の基本が2行並ぶ |
| Compare Changes | 2つを並べて見る | 内容は変わらない |
料金表の行は、Accept Both Changes だと講座が2行に増えて間違いになります。今回のように片方の一部ずつを生かすなら、どちらかを押したあと手で直すか、「Resolve in Merge Editor」で3画面の編集に切り替えます。Incoming、Current、Result の3つの欄が出て、Result が最終形です。
- 競合を直して保存する
- 3画面の編集なら「Complete Merge」を押す。そうでなければ Source Control の画面で「Stage Changes」の + を押す
- Source Control の画面からコミットする
Complete Merge はそのファイルを git add した状態にするだけで、合流はまだ終わっていません。3までやって完了です。

AIに任せるときの注意
Claude Code や GitHub Copilot に頼めば、記号を消す作業は済みます。問題は「どちらを残すか」で、これは料金を決めた人にしか分かりません。AIに任せると、記号はきれいに消えて、片方の変更だけが静かに消えていることがあります。VS Codeの「Resolve Merge Conflict with AI」のような機能も、公式に提案を見直してからステージするよう書かれています。2026年11月時点では実験的な機能で、GitHub Copilotが使える環境でしか動きません。
確かめ方は簡単です。合流の記録を作ったあと、push する前に次の2つを見ます。HEAD^1 は合流前の main、HEAD^2 は入ってきた枝です。
$ git diff HEAD^1 HEAD
diff --git a/menu.html b/menu.html
index 4878dd7..721c5c9 100644
--- a/menu.html
+++ b/menu.html
@@ -1,6 +1,6 @@
<h1>料金表</h1>
<table>
-<tr><td>和食の基本(全4回)</td><td>6,200円</td></tr>
+<tr><td>和食の基本(全4回)</td><td>6,500円</td></tr>
<tr><td>家庭の洋食</td><td>6,500円</td></tr>
<tr><td>親子パン教室</td><td>4,800円</td></tr>
<tr><td>季節の和菓子</td><td>5,200円</td></tr>
$ git diff HEAD^2 HEAD
diff --git a/menu.html b/menu.html
index 5938e85..721c5c9 100644
--- a/menu.html
+++ b/menu.html
@@ -1,6 +1,6 @@
<h1>料金表</h1>
<table>
-<tr><td>和食の基本</td><td>6,500円</td></tr>
+<tr><td>和食の基本(全4回)</td><td>6,500円</td></tr>
<tr><td>家庭の洋食</td><td>6,500円</td></tr>
<tr><td>親子パン教室</td><td>4,800円</td></tr>
<tr><td>季節の和菓子</td><td>5,200円</td></tr>
1つ目は代表の版から見て変わった点で、金額がBの6,500円になりました。2つ目はBの版から見て変わった点で、名前が「全4回」になりました。片方の差分が空なら、その版をそのまま採用して、もう片方の変更を捨てた印です。空でなくても、残った行が意図どおりかは読んで確かめます。AIには「どちらをどう残したか、1件ずつ書いてください」と頼むと、この確認が早く済みます。
Excelや画像は混ぜられません
テキストのファイルは行で比べられますが、Excelや画像のようなバイナリ(文字ではないデータ)は比べられません。記号も入らず、次の表示が出ます。
$ git merge excel-b
warning: Cannot merge binary files: price.xlsx (HEAD vs. excel-b)
Auto-merging price.xlsx
CONFLICT (content): Merge conflict in price.xlsx
Automatic merge failed; fix conflicts and then commit the result.
直し方は、どちらか一方を丸ごと選ぶだけです。--theirs は入ってくる枝の版、--ours は今いる枝の版です。
$ git restore --theirs price.xlsx
$ git add price.xlsx
$ git commit
[main d909903] Merge branch 'excel-b'
選ばなかった側の変更は、選んだファイルに手で入れ直します。みんなで書き換える表はGitに入れず、Googleスプレッドシートなど同時編集できる場所に置くほうが向いています。images/ の写真も同じで、同じファイル名を2人が差し替えると一方しか残せません。
減らす方法
コンフリクトをなくすことはできませんが、数は減らせます。
- 枝を短くする。何週間も放置した枝ほど、main との差が開きます。実際に運用していると、1つの修正に1つの枝で、その日か翌日に合流する形だとほとんど起きません
- 始める前に pull する。main を最新にしてから枝を作ります
- 同じファイルを同時に触らない。料金表を直す間はBに一言伝えるだけで避けられます
- 整形だけの変更を混ぜない。全行の字下げを変えると、全行が競合の対象になります
できないことと、その代わり
| できないこと | その代わり |
|---|---|
| Gitに正しいほうを決めてもらう | 内容を決めた人に聞く。-X ours という指定は競合した箇所だけ自分側を自動で採用し、相手の変更が静かに消える。AIに任せたときと同じ危険があるので、普段は使わなくていい |
| Excelや画像を混ぜる | 一方を選び、もう一方は手で入れ直す。表はスプレッドシートに置く |
| 複雑な競合をGitHubの画面で直す | 手元のコマンドかVS Codeで直す |
| 競合がないことで内容の正しさを保証する | 合流後に画面と差分を見る |
よく詰まるところ
| 症状 | 原因 | 直し方 |
|---|---|---|
Committing is not possible because you have unmerged files. | 直したファイルを add していない | 直して git add してからコミットする |
Pulling is not possible because you have unmerged files. | 合流の途中で pull した | 先に直して終わらせるか、git merge --abort する |
公開したページに <<<<<<< が出た | 記号を消さずに add した。Gitは止めてくれない | 下の検査で探し、直してコミットする |
| 編集画面が開いて操作できない | git commit がメッセージの編集画面を開いた | Vimなら :wq と入力してEnter。先に git commit --no-edit を使えば開かない |
Your local changes to the following files would be overwritten by merge | コミットしていない変更と pull がぶつかった | 先にコミットしてから pull する |
fatal: Need to specify how to reconcile divergent branches. | 手元とGitHubの両方に別のコミットがある | git pull --no-rebase で合流させる。競合が出たらこの記事の手順で直す |
| 記号の上下が逆に見える | git pull --rebase の途中では、HEAD が相手の版で下が自分の版になる | 落ち着いて中身で判断する。やめるなら git rebase --abort |
CONFLICT (modify/delete) | 片方が変え、片方が消した | 残すなら git add、消すなら git rm してコミットする |
記号が残ったままでも git add も git commit も通ってしまいます。次の検査で見つけられます。
$ git diff --cached --check
menu.html:5: leftover conflict marker
menu.html:7: leftover conflict marker
menu.html:9: leftover conflict marker
$ git grep -n "<<<<<<<"
menu.html:5:<<<<<<< HEAD
1つ目は add した直後、2つ目はコミットしたあとでも使えます。
次に読む
枝と合流の基本は「git branchとmergeの使い方:枝を分けて合流する、GitHub Flowまで」にあります。GitHubの画面での流れ全体は「プルリクエストとは:作り方・レビュー・マージの流れ」で確かめられます。合流したあとで間違いに気づいたら「Gitで元に戻す:revert・reset・restoreの違いと使い分け」を開きます。pull の使い分けは「git clone・pull・fetchの違い:受け取る操作の使い分け」に続きます。