git コンフリクト解決の手順:マーカーの読み方からrerereと再発防止まで
git のマージ衝突を直す具体的な手順。コンフリクトマーカーの読み方、ours/theirsの罠、rerereでの自動再利用、衝突を減らす運用、Claude Codeへの頼み方まで実例で。
git merge を叩いた瞬間、ターミナルが赤くなる。
CONFLICT (content): Merge conflict in src/auth.ts。心臓がきゅっとなる、あの感じ。僕も最初の数年は、コンフリクトが出るたびに「うわ、やっちゃった」と固まっていました。とりあえず片方を --ours で潰して、動いたから良し——としていたら、本番で認証が壊れました。消したのは「消してはいけない側」でした。
コンフリクトは事故じゃありません。Gitが「ここは機械じゃ決められないから、君が決めて」と正直に渡してきている状態です。怖いのは衝突そのものじゃなく、中身を読まずに片方を捨てること。この記事では、マーカーの読み方から、ありがちな罠、同じ衝突を二度と手で解かない rerere、そして衝突を減らす運用までを、僕が普段やっている順番で書きます。
ブランチをどう切るか(trunk-based か git-flow か、rebase か merge か)という設計の話は、姉妹記事の Gitブランチ戦略の選び方 に分けました。ここは「もう衝突した。どう直す?」に集中します。
この記事の要点
- コンフリクトマーカーは3行(
<<<<<<</=======/>>>>>>>)。上が自分(HEAD)、下が相手。まず3行を消すのではなく、両方の意図を読む。 ours/theirsは merge と rebase で逆になる。コマンドで片方を採用する前に必ずgit statusを見る。- 迷ったら戻れる。
git merge --abortで衝突前の状態に巻き戻せる。これを知っているだけで落ち着ける。 - 同じ衝突を繰り返すなら
git config --global rerere.enabled true。一度解いた解決を記録し、次から自動で再適用してくれる。 - 衝突は「小さく・頻繁にマージ」で激減する。Claude Codeには丸投げせず「方針を渡して作業させ、人間が差分とテストで締める」。
なぜ衝突するのか:3行マーカーの正体
コンフリクトは、2つのブランチが「同じ行のあたり」を別々に書き換えたときに起きます。違う行を触っている分にはGitが勝手に混ぜてくれる。重なったときだけ、こうなります。
<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> feature/login
読み方はこうです。
<<<<<<< HEADから=======まで → いま自分がいるブランチ(HEAD)側の中身。=======から>>>>>>> feature/loginまで → 取り込もうとしている相手の中身。- この3つのマーカー行は、最終的に1本残らず消す。残っているとコードとして壊れます。
ここで大事なのは、「3000 と 5000、どっちが正しいか」を決めるのは設計判断だということ。Gitは値の意味を知りません。タイムアウトを伸ばした理由が相手側にあるなら 5000 を、こっちのバグ修正が 3000 なら 3000 を残す。文字を消す作業ではなく、意図を選ぶ作業です。
diff3 にすると「元の値」が見える
デフォルトの表示だと「自分」と「相手」しか出ません。でも本当に知りたいのは多くの場合「もともと何だったか」です。設定を変えると、共通の祖先(base)も並びます。
git config --global merge.conflictStyle zdiff3
すると衝突がこう見えます。
<<<<<<< HEAD
const timeout = 3000;
||||||| base
const timeout = 1000;
=======
const timeout = 5000;
>>>>>>> feature/login
真ん中の ||||||| が元の値(1000)です。「自分は3000に、相手は5000に変えた。元は1000」と分かると、判断が一気に楽になります。zdiff3 は diff3 の改良版で、両側で一致している行を衝突範囲から外してくれるぶん見やすい。僕はグローバルに入れっぱなしです。これは Git 公式の merge ドキュメント に載っている標準機能です。
解決の基本手順:迷ったら戻れる、を最初に
衝突が出たら、いきなりエディタを開く前に状態を固定します。ここを飛ばすと、解決中に別の未コミット変更を巻き込んで、レビュー不能な差分ができます。
git status --short # 作業途中のファイルが混ざっていないか
git branch --show-current # 今どのブランチにいるか
git diff --name-only --diff-filter=U # 未解決の衝突ファイルだけ一覧
--diff-filter=U の U は Unmerged の頭文字。未解決のファイルだけを出してくれる、地味だけど一番使うコマンドです。これで対象が3つなのか30個なのかが分かる。
ここからの流れはいつも同じです。
git diff --name-only --diff-filter=Uで対象を把握する。- ファイルを開き、マーカーの上下を読んで、残す中身を決める(必要なら両方を統合する)。
- 3つのマーカー行をすべて消す。
git add <ファイル>で「解決済み」とGitに伝える。- 全部解決したら
git diff --checkで残骸を確認 → テスト → コミット(rebase中ならgit rebase --continue)。
そして最初に覚えてほしいのが、逃げ道です。
git merge --abort # マージの衝突を、衝突する前の状態に巻き戻す
git rebase --abort # rebase中ならこちら
Git 公式によれば git merge --abort は「マージ前の状態を復元しようとする」コマンドで、実質 git reset --merge と同じ動きです。「最悪 --abort すれば元に戻る」と知っているだけで、手が震えなくなります。僕が新人に最初に教えるのもこれです。
ありがちな罠:ours と theirs は逆になる
一番事故るのが git checkout --ours / --theirs の取り違えです。「ours=自分」と単純に覚えていると、痛い目を見ます。
| 状況 | ours(こちら側)が指すもの | theirs(向こう側)が指すもの |
|---|---|---|
git merge feature 中 | いまいるブランチ(取り込む側) | 取り込まれる feature |
git rebase main 中 | 積み替え先の main | 自分のコミット |
rebase は「自分のコミットを、相手の上に1個ずつ積み替える」操作です。だから視点が反転して、ours が main、theirs が自分の変更になる。直感と逆です。冒頭で僕が認証を壊したのは、まさにこれ。rebase 中に「自分の修正を残すつもりで --ours」を打ち、main 側の変更を採用してしまいました。
対策はシンプルで、片側を丸ごと採用する前に必ず git status と差分を見ること。そして基本は --ours / --theirs で潰すのではなく、中身を読んで手で統合する。ショートカットは、本当に「片方が完全に正しい」と確信できるときだけ使います。
同じ衝突を二度解かない:git rerere
長いブランチを何度もリベースしていると、まったく同じ衝突に毎回ぶつかることがあります。一度解いたのに、また出る。これを自動化するのが rerere(reuse recorded resolution=記録した解決の再利用)です。
git config --global rerere.enabled true
これを入れておくと、Gitは衝突を解決した内容を裏側のデータベースに記録します。同じ形の衝突が次に出たとき、前回の解決を自動で再適用してくれる。Git 公式の rerere ドキュメント によれば、ブランチをマージする順番が違っても、別のブランチで同じ衝突になっても、記録した解決を引っ張ってこられます。
実際の効き目はこんな感じです。長期 feature ブランチで git rebase main を週次でやると、同じファイルの同じ箇所が毎回ぶつかる。rerere を入れてからは、2回目以降「Resolved ‘src/routes.ts’ using previous resolution」と表示され、僕は差分が正しいか確認するだけになりました。手で解く回数が体感で半分以下です。
注意点も書いておきます。rerere は「過去の解決」を機械的に当てるので、前回の判断が間違っていたら、その間違いごと再適用します。だから自動で解決されたあとも git diff には必ず目を通す。間違いを記録してしまったら git rerere forget <ファイル> で忘れさせて、解き直します。
マージツールという選択肢
マーカーを手で消すのがつらい大きな衝突は、3画面(自分・相手・結果)で見えるマージツールが速いです。
git mergetool # 設定済みのツールを起動
git config --global merge.tool vscode # VS Code を使う例
git config --global mergetool.vscode.cmd 'code --wait --merge $REMOTE $LOCAL $BASE $MERGED'
VS Code なら、衝突箇所に「Accept Current(自分)/ Accept Incoming(相手)/ Accept Both(両方)」のボタンが出ます。||||||| base を有効にしておくと、ここでも元の値が見えて判断が速い。ただしツールはあくまで表示を助けるだけで、何を残すかを決めるのは結局あなたです。ボタンを脳死で押すと、手でマーカーを消すのと同じ事故が起きます。
git mergetool を実行すると .orig というバックアップが残ることがあります。邪魔なら git config --global mergetool.keepBackup false で無効化できます。
衝突を「減らす」運用:小さく、頻繁に
ここまで解き方を書きましたが、本音を言うと一番効くのは「衝突しにくくする」ことです。直し方より、出さない工夫。
- 小さく頻繁にマージする。 2週間ぶりに main を取り込むと衝突は山になる。毎日
git fetch && git merge origin/main(または rebase)していれば、1回あたり数行で済みます。差分が小さいほど、判断ミスも減る。 - PRを小さく分ける。 1つのPRで20ファイル触ると、誰かと必ずぶつかる。機能ごとに細かく出す。
- 「よくぶつかる場所」を構造で分ける。 ルート定義、権限設定、設定ファイル、スキーマは衝突の常連です。例えば
src/routes.tsが毎週ぶつかるなら、ルートを機能別ファイルに割る。依存追加だけの専用PRを作る、というのも効きます。 - チームの方針を
CLAUDE.mdやドキュメントに残す。 「セキュリティ修正は必ず残す」「lockfileは手で直さず再生成」を共有しておくと、解決の判断がブレません。詳しくは CLAUDE.mdベストプラクティス を。
衝突解決のスキルを磨くより、衝突する量を減らすほうが、長い目で見て圧倒的に楽です。
Claude Code に解決を手伝わせる
衝突解決はAIが手伝える作業です。ただし丸投げは禁物。構文上きれいに直しても、業務ルールやチームの優先順位を間違えることがあるからです。コツは「方針を先に渡し、作業させ、人間が差分とテストで締める」。
Claude Code の CLI は claude -p "依頼内容" で非対話実行できます(CLI リファレンス)。下は、未解決ファイルだけを対象に、優先順位と禁止事項を渡して解いてもらう例です。そのままコピペで動きます。
#!/usr/bin/env bash
set -euo pipefail
# 1. 未解決の衝突ファイルがあるか確認(なければ何もしない)
unmerged=$(git diff --name-only --diff-filter=U)
if [ -z "$unmerged" ]; then
echo "未解決の衝突はありません。"
exit 0
fi
echo "対象ファイル:"
echo "$unmerged"
# 2. 方針つきプロンプトを作る(ヒアドキュメント)
plan=$(cat <<'PROMPT'
git のコンフリクトを解決してください。
前提:
- 対象は `git diff --name-only --diff-filter=U` で出る未解決ファイルだけ。
- origin/main のセキュリティ修正・権限チェック・型定義は必ず残す。
- feature 側の新しい画面・API呼び出し・テストも残す。
作業:
1. 各ファイルの衝突理由を一行で説明する。
2. マーカー(<<<<<<<, =======, >>>>>>>)を消し、両方の意図が残る形に統合する。
3. 同じ責務の実装が二重になったら片方に統合する。
4. 終わったら git diff --check で空白エラーを確認する。
禁止:
- 無関係なリファクタリングをしない。
- 片方の変更を黙って捨てない。
- package-lock.json は手で編集しない(依存を確定後に再生成する想定)。
PROMPT
)
# 3. Claude Code に渡す
claude -p "$plan"
# 4. 人間側で必ず締める
git diff --check
echo "→ git diff で内容を確認し、問題なければ git add → コミット(rebase中は git rebase --continue)"
ポイントは、解決そのものだけでなく「衝突理由の説明」を求めること。説明が薄いときは、AIがコードの意味を追えていないサインです。そのまま信じず自分で読み直します。lockfileのような生成ファイルは「手でマージせず、元ファイルを直してから再生成」と必ず指示する。package.json は両方の依存を残したのに package-lock.json だけ片側に寄せると、ローカルでは動いてもCIで依存解決が変わって落ちます。
毎回同じ注意を打つのが面倒なら、Hooks で機械チェックを自動化できます。例えば merge / rebase の後に必ずテストを走らせる、といった設定です。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash(git merge*)|Bash(git rebase*)",
"hooks": [
{ "type": "command", "command": "git diff --check && npm test" }
]
}
]
}
}
書き方の詳細は Claude Code Hooks入門、チームでの運用は Claude Codeチーム活用ガイド にまとめてあります。
よくある質問
Q. コンフリクトマーカーを消し忘れたまま add してしまいました。
A. git diff --check を実行すると、残ったマーカー(<<<<<<< など)や空白エラーを検出できます。CIに組み込んでおくと、マーカー入りのコードをpushする事故を防げます。
Q. 解決の途中で何が何だか分からなくなりました。やり直せますか?
A. はい。merge 中なら git merge --abort、rebase 中なら git rebase --abort で、衝突する前の状態に戻せます。慌てて中途半端にコミットするより、一度戻して落ち着いてからやり直すほうが速いです。
Q. git checkout --ours で片方を採用したら、必要な変更が消えました。
A. rebase 中は ours が「積み替え先(main側)」を指すため、自分の変更を残すつもりが逆になりがちです。片側を丸ごと採用する前に git status と git diff で向きを確認し、基本は手で統合してください。消してしまった場合は git rebase --abort で戻せます。
Q. rerere を有効にしたら、勝手に間違った解決をされませんか?
A. rerere は過去の解決を再適用するだけなので、前回が正しければ正しく、前回が間違っていればその間違いを再現します。自動解決後も git diff を必ず確認し、おかしければ git rerere forget <ファイル> で記録を消して解き直します。
Q. lockfile(package-lock.json など)が衝突しました。手でマージすべき?
A. しないでください。package.json など元ファイルの衝突を先に解決し、依存が確定してから npm install で lockfile を再生成します。手編集はCIとローカルで依存がずれる原因になります。
まとめ
コンフリクトは、Gitが「ここは人間が決めて」と渡してきた合図です。怖がって片方を潰すのではなく、マーカーの上下を読み、元の値(zdiff3)も見て、意図を選ぶ。迷ったら git merge --abort で戻れる。同じ衝突を繰り返すなら rerere に覚えさせる。そして根本的には、小さく頻繁にマージして衝突自体を減らす。
僕の検証では、15ファイルほどのTypeScriptプロジェクトで、方針なしにAIへ丸投げするとテスト修正の抜けが出ました。逆に「優先順位・触ってよい範囲・再生成方針・完了条件」を先に渡し、最後の git diff とテストだけ自分で見る運用にしたら、レビュー時間がはっきり短くなりました。まずは小さな feature ブランチで、git diff --name-only --diff-filter=U → 方針つきプロンプト → npm test の3点セットから試してみてください。
ブランチの切り方そのものを見直したくなったら Gitブランチ戦略の選び方 へ。チーム全体でClaude Codeの運用を整えたい方は 研修・相談 も覗いてみてください。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeに1ファイルだけ直させる指示文のつくり方
「もっと良くして」で40行も変えられた失敗から学んだ、触る範囲・検証・戻し方をセットにしたClaude Code用の依頼文テンプレートを紹介します。
Claude Code の権限拒否から復旧する: 止まった理由を次の安全手順に変える
Claude Code のコマンドが拒否されたとき、焦って許可を広げずに、拒否理由、代替手順、証拠コマンド、再試行条件へ分解する方法。
Claude Codeにビルド→スモークテスト→自動修正を回させる足場の作り方
最小スモークテストの選び方、失敗ログを食わせて直させるループ、回数上限と確認ゲートで暴走を止める方法を、コピペで動くコード付きで紹介します。