
AIにGitのコンフリクト解消を手伝わせる|壊さないマージの確認手順
金曜の夕方、そろそろ帰ろうかというタイミングで git pull。返ってきたのは「CONFLICT」の文字。ファイルを開くと <<<<<<< と ======= が並んでいて、どこから触ればいいのか一瞬固まる——あの感じ、ありますよね。
こういうとき、AIに丸ごと貼って「直して」とお願いしたくなります。実際、AIはとても上手に片づけてくれます。マーカーはきれいに消えて、コードは通る。ただ、そこで消えているものがあることに、あとから気づくことがあります。この記事では、いま何が起きているのかを共有したうえで、AIに手伝ってもらいながら「片側の変更を落とさない」ための確認手順を整理します。
結論:Gitのコンフリクト解消をAIに手伝わせるときの要点は3つです。①解消の前に「自分側と相手側が、それぞれ何をしたかったか」を1行で言えるようにする。②AIにはマーカーの中身だけでなく「もとの状態(分かれる前の共通の内容)」も渡す——git config --global merge.conflictStyle zdiff3 を一度設定しておくと、これが自動で見えるようになります。③解消したあとは「マーカーが消えたか」ではなく「片側の変更が消えていないか」で確認する。AIが得意なのは「マーカーのない、それらしいコードを作ること」であって、「両方の意図を守ること」ではありません。そこだけ人が持てば、あとは任せられます。
いきなり全部は要りません。 まずは②の設定を1行入れるところからで大丈夫です。
何が起きているのか——AIには「意図」が渡っていない

まず、なぜここだけ気を張る必要があるのかを共有させてください。理由は3つあります。
1つ目は、コンフリクトマーカーが「文字の違い」しか運んでいないこと。Gitが既定で見せてくれるのは、自分側と相手側の2つだけです。分かれる前のもとの状態は表示されません。ここが抜けると、片方が「行を足した」のか、もう片方が「行を消した」のかが区別できません。人が読んでも判断が割れるものを、そのままAIに渡していることになります。
2つ目は、AIが「マーカーのないコード」を作るのが得意なこと。これは弱点ではなく、まさに得意分野です。両方の書き方を混ぜて、構文としては正しく、それらしく辻褄の合ったコードを作れます。ただ、「両方の意図を守れているか」は、渡していない情報なので判断のしようがありません。結果として、片側の変更が静かに消えても、見た目には完成した状態になります。
3つ目は、Gitがコンフリクトとして報告しない衝突があること。たとえば、自分が関数の引数を1つ増やし、相手が別のファイルからその関数を新しく呼び足した——行が離れていれば、Gitは何も言わずに自動でマージします。マーカーは1つも出ないのに、動きません。「マーカーを消す作業」だけを終わりの合図にしていると、ここが素通りになります。
この3つが重なると、「コンフリクトは解消できたのに、あとで壊れている」が起きます。逆に言えば、もとの状態を見せて、意図を言葉で添えて、解消後に両側から差分を見る——これだけで、かなり防げるということです。
具体例——こんなふうに、片側が消える
実際に起きやすいのは、次のような形です。一つでも心当たりがあれば、この記事はそのまま使えます。
- どちらでもない値になる:同じ設定値を、自分は30から60へ、相手は30から10へ変えていた。混ぜようとすると、どちらの意図でもない中間の数字が入ることがあります。数値のコンフリクトは「足して2で割る」が通用しない場所です。
- 消したはずの処理が復活する:相手が「もう使わない」と判断して削除した処理を、自分は残したまま手直ししていた。両方を活かす形でまとめると、消したはずの処理がそのまま戻ります。もとの状態が見えていれば「これは削除だ」と分かるのですが、既定の表示では削除と追加の見分けがつきません。
- import・定義のかたまりが太る:両側で行が増えている箇所は、AIは基本的に全部並べます。使われていない読み込みや、重複した定義がそのまま残ることがあります。
- まとめて投げて、粒度が落ちる:20ファイルにコンフリクトが出ると、全部まとめて渡したくなります。1ファイルずつなら気づけたことが、まとめると「全体としてそれっぽい」結果に埋もれます。差分を追う難しさはAIに複数ファイルの変更を任せる|差分を見失わない追い方と同じ構図です。
- マーカーは出ないのに壊れる:前述の意味的な衝突です。ビルドが通ってしまう場合もあり、テストでしか見つかりません。
どれも、手を抜いた結果ではありません。コンフリクトが出たということは、同じ場所で二人とも仕事をしたということです。そこは責める場所ではなく、丁寧に扱う場所です。
影響——気づくのが、だいぶあとになる
コンフリクトの取り違えが厄介なのは、その場で失敗として現れにくいところです。
- 消えた変更は、しばらく誰も気づかない:相手の1行が落ちていても、その箇所を通るテストがなければ何も起きません。数日後に「あの修正、入ってましたっけ」と聞かれて、初めて分かります。
- 履歴からも追いにくい:マージのときに何をどう選んだかは、あとから差分だけを見てもかなり読みにくい部分です。レビューでも見落とされやすく、「誰も間違いに気づけない変更」になりがちです。
- 時間がないときほど出る:リリース前、長く伸びた枝を戻すとき、金曜の夕方。落ち着いて考えたいときに限って重なります。
ただ、ここは強調しておきたいところなのですが、マージはやり直せます。コミットする前なら git merge --abort で、着手前の状態にまるごと戻せます。コミットしたあとでも、git reflog を見ればマージ前の位置がそのまま残っています。「間違えても戻れる」と分かっているだけで、判断はかなり落ち着きます。焦って混ぜるより、一度戻して仕切り直す方が、たいてい速いです。
なお、戻すために使うコマンドの中には、手元の変更ごと消えるものもあります。実行前の確認の考え方はAIにコマンドを書かせて事故らない|破壊的コマンドを弾く確認の型にまとめてあります。
明日からやること(3ステップ)
大きな運用変更は要りません。この順番で、今日から小さく始められます。
- もとの状態が見えるようにする(設定1行):
git config --global merge.conflictStyle zdiff3を一度実行しておきます(Git 2.35以降で使えます。それより前のバージョンならdiff3を指定してください)。以後、コンフリクトの表示に|||||||で区切られたもとの状態が入るようになります。自分側・相手側・もとの3つが揃うと、「どちらが足したのか、どちらが消したのか」が読めるようになります。人が読むときにも、AIに貼るときにも、同じだけ効きます。この記事で一番効く一手は、これです。 - AIに渡す前に、両側の意図を1行ずつ書く:コンフリクト中に
git log --merge -p -- <ファイル名>を実行すると、そのファイルに触れた両側のコミットだけを差分つきで見られます。読んだら、「自分側=〇〇をしたかった」「相手側=〇〇をしたかった」と1行ずつメモします。この2行が、この作業でいちばん価値のある成果物です。そのうえでAIには、①もと・自分・相手の3つを含むコンフリクト箇所、②この意図2行、③周辺のコードを渡します。ファイルは1つずつで。文脈の渡し方はAIコーディングは小さく切る|関数1個から始めるスコープ設計と同じ考え方です。
そのまま使える頼み方の例:
> 以下はGitのコンフリクト箇所です。||||||| の上が自分側、その下がもとの状態、======= の下が相手側です。 > 自分側の意図:(1行) > 相手側の意図:(1行) > 両方の意図を満たす解消案を出してください。両立できない場合は、勝手にどちらかへ寄せず、両立できない理由を先に説明してください。 最後に「どちらの変更をどう扱ったか」を箇条書きで示してください。
「両立できないときは言って」と先に伝えておくのが、地味ですがよく効きます。AIは黙って辻褄を合わせられてしまうので、判断が要る場所を報告させる約束にしておきます。
- コミットする前に、両側から差分を見る:解消したら、まだコミットせずに次の2つを見ます。
git diff HEAD -- <ファイル名>は自分側から見た差分、git diff MERGE_HEAD -- <ファイル名>は相手側から見た差分です。相手の変更が落ちていれば、後者に「元に戻した形」でくっきり出ます。ここで、②で書いた意図2行が両方とも満たされているかを確かめます。そのあとでビルドとテストへ。マーカーが出なかった意味的な衝突は、ここでしか見つかりません。既存テストの活かし方はAIに直させてもリグレッションを出さない既存テストの渡し方が下敷きになります。
補足として、rebaseなどで同じコンフリクトを何度も解く場合は、git config --global rerere.enabled true を入れておくと、一度解いた解消をGitが覚えて再利用してくれます。便利ですが、1回目の解消が正しかったことが前提になるので、最初の1回だけは、いつもより丁寧に見ておくのがおすすめです。
3つとも今日やる必要はありません。1だけでも、次のコンフリクトの読みやすさがはっきり変わります。
コンフリクト解消のチェックリスト
全部に○が要るわけではありません。気になった行だけで十分です。
① 解消の前に
-
merge.conflictStyleがzdiff3(またはdiff3)になっているか - 自分側の変更が何をしたかったか、1行で言えるか
- 相手側の変更が何をしたかったか、1行で言えるか
- 判断に迷ったら
git merge --abortで戻せる、と分かっているか
② AIに渡すとき
- マーカーの中身だけでなく、もとの状態も一緒に渡しているか
- 両側の意図を、言葉で添えているか
- ファイルを1つずつ渡しているか(まとめて投げていないか)
- 「どちらをどう扱ったか」を説明させているか
- 「両立できないときは、寄せずに報告して」と伝えているか
③ コミットする前に
-
git diff MERGE_HEAD -- <ファイル>で、相手の変更が消えていないか見たか -
git diff HEAD -- <ファイル>で、自分の変更が消えていないか見たか -
<<<<<<<=======>>>>>>>の残りをファイル全体で検索したか - 使われていない読み込みや、重複した定義が残っていないか
- 設定値・数値が「どちらの意図でもない値」になっていないか
- ビルドとテストを通したか(マーカーが消えた=マージ成功、ではない)
この記事のまとめ
AIはコンフリクトの解消がとても得意です。ただ、得意なのは「マーカーのない、それらしいコードを作ること」であって、「両方の意図を守ること」ではありません。意図は、こちらが渡さない限り届かないからです。
やることは3つだけです。①merge.conflictStyle を zdiff3 にして、もとの状態を見えるようにする/②両側の意図を1行ずつ書いてから渡す/③コミット前に git diff MERGE_HEAD で相手側から見直す。この3つがあると、コンフリクトは「地雷を踏まないよう祈る作業」から、「読んで決める作業」に変わります。

コンフリクトが出るのは、同じ場所を二人が本気で触ったからです。それを片方に寄せず、両方の仕事を残そうとして手を止められる人は、チームの中でかなり信頼される人だと思います。今日その手間をかけた分は、誰かの数日を確実に助けています。