レシピ#6-3: マージコンフリクト(競合)を解決する
チームで開発を進めたり、オープンソースプロジェクトに貢献していると、いつか必ずマージコンフリクト(Merge Conflict)という壁にぶつかります。
ターミナルに赤文字でCONFLICTと表示されると、多くの開発者はパニックに陥りますが、心配する必要はありません。コンフリクトは「エラー」ではなく、「Gitがあなたに判断を求めている正常な状態」です。
このレシピでは、マージコンフリクトがなぜ起こるのか、そしてそれを冷静に解決するための手順を学びます。
1. なぜコンフリクトは起こるのか?
コンフリクトは、「同じファイルの、同じ行(または非常に近い行)を、複数の人が別々に変更した」場合に発生します。
Gitは非常に賢いですが、2人の開発者が行った変更の「どちらが正しいか」を自動で判断することはできません。
- あなた:
main.dartの20行目のAppBarのタイトルを「マイアプリ」に変更した。 - 同僚: 同じく
main.dartの20行目のAppBarのタイトルを「最高のアプリ」に変更した。
あなたが同僚の変更を取り込もうとした(git pullやgit merge)時、Gitはこう考えます。
「待ってくれ!20行目のタイトルは『マイアプリ』なのか?それとも『最高のアプリ』なのか?私には判断できない。人間よ、どちらが正しいか、あるいは両方を組み合わせるのか、決めてくれ!」
これが、マージコンフリクトの正体です。
2. コンフリクトの解決プロセス (VS Codeを使った方法)
VS Codeのようなモダンなエディタには、コンフリクトを視覚的に解決するための強力なツールが組み込まれています。
Step 1: コンフリクトの発生を認識する
git pullやgit mergeを実行した際に、以下のようなメッセージが表示されたら、コンフリクトが発生しています。
Auto-merging lib/main.dart
CONFLICT (content): Merge conflict in lib/main.dart
Automatic merge failed; fix conflicts and then commit the result.
VS Codeの左側のソース管理パネルを見ると、コンフリクトが発生したファイルが「Merge Changes」セクションに表示されます。
Step 2: コンフリクト箇所を確認する
コンフリクトが発生したファイル(例: lib/main.dart)を開くと、以下のような特殊なマーカーで囲まれた箇所が見つかります。
<<<<<<< HEAD
// あなたが行った変更 (現在のブランチの変更)
appBar: AppBar(
title: const Text('マイアプリ'),
),
=======
// 取り込もうとした変更 (相手のブランチの変更)
appBar: AppBar(
title: const Text('最高のアプリ'),
),
>>>>>>> feature/new-title
<<<<<<< HEAD: ここからが、あなたの変更(HEADが指す、現在のブランチの変更)です。=======: あなたの変更と、相手の変更の区切り線です。>>>>>>> feature/new-title: ここまでが、取り込もうとした相手のブランチ(この例ではfeature/new-title)の変更です。
Step 3: AIにコンフリクトを解決してもらう(推奨)
このCookbookの基本方針は「コードはAIに書いてもらう」です。コンフリクト解決も同じで、まずAIに任せましょう。
Claude CodeやCursorを使っていれば、コンフリクトしたファイルを直接読ませて解決させることができます。コードを貼り付ける必要はありません。
lib/main.dart でマージコンフリクトが発生しています。
両方の変更の意図を確認して、コンフリクトを解決してください。
判断に迷う箇所があれば、解決方針を先に説明してください。
AIがコンフリクトマーカーを削除し、両方の変更を適切に組み合わせたコードに整えてくれます。解決結果を確認したら、Step 6(ステージング)に進みます。
Step 4: (手動で仕上げたい場合) どちらの変更を採用するか決定する
自分の手で解決したい場合や、AIの解決結果を微調整したい場合は、VS Codeの機能を使います。VS Codeは、このコンフリクト箇所の上に、便利な選択肢を表示してくれます。
- Accept Current Change: あなたの変更(
HEAD側)を採用します。「マイアプリ」が残ります。 - Accept Incoming Change: 相手の変更(Incoming側)を採用します。「最高のアプリ」が残ります。
- Accept Both Changes: 両方の変更を上下に残します。
- Compare Changes: 変更内容を左右に並べて比較表示します。
多くの場合、「Current」か「Incoming」のどちらかをクリックするだけで解決します。
Step 5: (上級編) 手動で編集する
場合によっては、両方の変更の良いとこ取りをしたい場合もあります。
- 例:あなたはタイトルを変更し、相手は背景色を追加した。
dart <<<<<<< HEAD appBar: AppBar( title: const Text('マイアプリ'), ), ======= appBar: AppBar( backgroundColor: Colors.blue, title: const Text('最高のアプリ'), ), >>>>>>> feature/new-title - この場合、上記のどのボタンも押さずに、手動でコードを編集します。
<<<<<<<,=======,>>>>>>>のマーカーをすべて削除し、最終的に残したいコードの形に自分で整えます。dart // 手動で編集した最終形 appBar: AppBar( backgroundColor: Colors.blue, title: const Text('マイアプリ'), // タイトルは自分の変更を採用 ),
Step 6: 解決したファイルをステージングする
コンフリクトを解決(ファイルを編集して保存)したら、「このファイルのコンフリクトは解決しましたよ」とGitに教える必要があります。
- VS Codeのソース管理パネルで、「Merge Changes」セクションにある解決済みのファイルの横の「+」アイコンをクリックして、ステージングします。
- または、ターミナルで以下のコマンドを実行します。
bash git add lib/main.dart
Step 7: マージコミットを作成する
すべてのコンフリクトを解決し、ファイルをステージングしたら、最後に「マージを完了させるための特別なコミット」を作成します。
ターミナルで、ただgit commitとだけ実行します。
git commit
これを実行すると、テキストエディタが開き、Merge branch 'feature/new-title'のような、デフォルトのコミットメッセージがすでに入力されています。通常は、このメッセージをそのまま保存してエディタを閉じればOKです。
これで、コンフリクトの解決は完了です!あなたのブランチは、相手の変更を取り込み、かつあなたの変更も保持した、きれいな状態になりました。
🤖 AI活用プロンプト (コンフリクト解決の相談)
Claude CodeやCursorなら、Step 3のように該当ファイルを直接読ませるだけでよく、貼り付けは不要です。Webチャット(claude.ai等)で相談する場合は、以下のようにコンフリクト箇所を貼り付けます。 ``` あなたはGitのマージコンフリクト解決の専門家です。
以下のコンフリクトが発生しました。それぞれの変更の意図を推測し、どのように解決するのが最も良いか、具体的なコードと共に提案してください。
diff (ここに、コンフリクトマーカーを含むコードブロックを貼り付ける)