Gitコンフリクト(競合)の解決手順:マージ・リベース時の対処法を図解で解説
目次
コンフリクトとは何か
Gitコンフリクト(競合)とは、同じファイルの同じ箇所を別々のブランチで異なる変更をした場合に、Gitがどちらを採用すればいいか判断できなくなった状態です。
main ブランチ: 「こんにちは」
feature ブランチ: 「Hello」
→ どちらを残す?Gitには判断できない → コンフリクト発生
コンフリクトは悪いことではありません。チーム開発では必ず発生するものです。適切に解決する手順を身につければ怖くありません。
コンフリクトが起きる仕組み
以下のような状況でコンフリクトが発生します。
A (main)
│
●──── 初回コミット(greeting.js を作成)
│
├────────────────────────────── (feature/greeting を作成)
│ │
● main: 「こんにちは」に変更 ● feature: 「Hello」に変更
│ │
└───────── マージ ───────────────┘
↓
コンフリクト発生!
git mergeやgit rebaseの実行時に、Gitが自動解決できない変更がある場合にコンフリクトが起きます。
コンフリクトマーカーの読み方
コンフリクトが発生すると、該当ファイルに次のようなマーカーが挿入されます。
function getGreeting() {
<<<<<<< HEAD
return 'こんにちは';
=======
return 'Hello';
>>>>>>> feature/greeting
}
| マーカー | 意味 |
|---|---|
<<<<<<< HEAD | ここから現在のブランチ(HEAD)の内容 |
======= | 境界線(ここで2つのバージョンが分かれる) |
>>>>>>> feature/greeting | ここまでマージしようとしたブランチの内容 |
重要: これらのマーカーはGitが挿入した目印です。解決後は必ずすべてのマーカーを削除してください。
手動でコンフリクトを解決する手順
Step 1: コンフリクト箇所を確認する
# マージを試みる
git merge feature/greeting
# コンフリクトしたファイルを確認
git status
# both modified: src/greeting.js ← コンフリクト中のファイル
# コンフリクトのあるファイルを一覧表示
git diff --name-only --diff-filter=U
Step 2: ファイルを開いて編集する
エディタでコンフリクトしているファイルを開き、3つのマーカー行を含む該当箇所を編集します。
パターン1: HEADの内容を採用する
// 解決後(こんにちはを採用)
function getGreeting() {
return 'こんにちは';
}
パターン2: マージするブランチの内容を採用する
// 解決後(Helloを採用)
function getGreeting() {
return 'Hello';
}
パターン3: 両方を組み合わせる(最も多いケース)
// 解決後(両方の内容を統合)
function getGreeting(lang = 'ja') {
return lang === 'en' ? 'Hello' : 'こんにちは';
}
Step 3: 解決したファイルをステージングしてコミット
# 解決したファイルをステージング
git add src/greeting.js
# マージコミットを作成
git commit
# エディタが開いてコミットメッセージを編集できる
# デフォルトのメッセージ「Merge branch 'feature/greeting'」でOK
# コミットを確認
git log --oneline --graph
コンフリクトが複数ファイルにある場合は、すべてのファイルを解決してからgit addしてください。
VSCode Merge Editorを使う
VSCode 1.69以降にはMerge Editorという専用のUIが組み込まれています。マーカーを手動で編集するより直感的に解決できます。
起動方法
コンフリクトが発生した状態でVSCodeを開くと、エクスプローラーペインで該当ファイルに「C」バッジが表示されます。
- コンフリクトしているファイルをクリックして開く
- エディタ上部に表示される「Resolve in Merge Editor」ボタンをクリック
Merge Editorの画面構成
┌─────────────────────────────────────────────────────┐
│ Current (HEAD) │ Incoming (マージ先) │
│ 「こんにちは」 │ 「Hello」 │
│ [Accept Current] │ [Accept Incoming] │
├─────────────────────────────────────────────────────┤
│ Result(結果) │
│ ここに最終的な内容が表示される │
│ 自由に編集可能 │
└─────────────────────────────────────────────────────┘
- Accept Current: 現在のブランチの変更を採用
- Accept Incoming: マージしてくるブランチの変更を採用
- Accept Both: 両方の変更を追加(順序は選択可能)
- Resultペインは直接編集できる
解決後の操作
Merge Editor上で解決が完了したら「Complete Merge」ボタンをクリックします。VSCodeのSource Controlパネルからそのままコミットできます。
リベース時のコンフリクト対処
git rebaseでもコンフリクトは発生します。マージとは対処方法が少し異なります。
git checkout feature/greeting
git rebase main
# コンフリクトが発生した場合
# CONFLICT (content): Merge conflict in src/greeting.js
# ファイルを編集して解決後
git add src/greeting.js
# リベースを続行(マージとは違いcommitではなくcontinueを使う)
git rebase --continue
# リベースを中断して元に戻す場合
git rebase --abort
マージとリベースのコンフリクト解決の違い:
| 操作 | コンフリクト解決後のコマンド |
|---|---|
git merge | git add → git commit |
git rebase | git add → git rebase --continue |
リベースは1コミットずつ適用するため、複数コミットに分散してコンフリクトが発生することがあります。各コンフリクトを解決してからgit rebase --continueを繰り返します。
コンフリクトを予防する方法
コンフリクトは完全に避けられませんが、頻度と規模を減らすことはできます。
1. ブランチを長く生かさない
featureブランチのライフサイクルを短くし、こまめにmainとの差分を縮めます。目安は2〜3日以内にマージかプルリクエスト。
2. 作業前に必ずpullする
# 作業開始前に最新のmainを取得
git checkout main
git pull origin main
git checkout feature/xxx
# または featureブランチ上でrebaseする
git rebase main
3. ファイルを適切に分割する
1つのファイルに機能を詰め込みすぎると、複数人が同じファイルを触ってコンフリクトが多発します。関心の分離(Single Responsibility)を意識してファイルを分割しましょう。
4. チームでの変更範囲を事前に共有する
同じ機能に複数人が触る場合は、事前にSlackやPRのコメントで「このファイルは私が担当」と共有するだけでコンフリクト率が下がります。
Pro Git 第2版
Gitの開発者Scott Chaconによる公式解説書。内部構造から実務的なワークフローまで深く学べる。電子版はGit公式サイトで無料配布されています。
※ アフィリエイトリンクを含みます
まとめ
Gitコンフリクトの対処法をまとめます。
- コンフリクトマーカー:
<<<<<<<(現在)/=======(境界)/>>>>>>>(マージ先)の3つを理解する - 手動解決: マーカーを見てどちら(または両方)を採用するか判断し、マーカーを削除して
git add→git commit - VSCode Merge Editor: GUIで直感的に解決でき、ResultペインでカスタマイJZもできる
- リベース時の違い:
git rebase --continueでコミットを1つずつ進める - 予防策: ブランチを短命に保ち、作業前のpull/rebaseを習慣化する
コンフリクトは「チームで同じ場所を同時に触っていた」という証拠です。チームのコミュニケーションが活発な証でもあります。正しい手順で解決できれば、怖いものではありません。