コンフリクト解消の実践
マージ・リベース時に発生するコンフリクトを、実際に発生させてから解消するまでを演習形式で学びます。
このチュートリアルでは、複数人での開発で避けて通れない「コンフリクト(衝突)」の発生から解消までを実践形式で学びます。コンフリクトは怖いものではなく、正しい手順を知っていれば落ち着いて対処できることを体験しましょう。
前提: ブランチの作成・マージ・rebase の基本操作ができることを前提とします。
演習 1:わざとコンフリクトを起こす
コンフリクトがどう発生するかを体験するため、意図的に同じファイルの同じ箇所を2つのブランチで変更します。
問題: 以下の手順でコンフリクトを発生させてください。
mainブランチのREADME.mdの1行目を"Hello"に変更してコミットmainから分岐したfeature/greetingブランチで、同じ1行目を"Hi"に変更してコミットfeature/greetingをmainにマージする
答えを見る
# 1. main で変更
git switch main
echo "Hello" > README.md
git commit -am "README を Hello に変更"
# 2. feature ブランチで別の変更
git switch -c feature/greeting main~1
echo "Hi" > README.md
git commit -am "README を Hi に変更"
# 3. main にマージを試みる
git switch main
git merge feature/greetingAuto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.同じ行を異なる内容に変更したため、Git はどちらを採用すべきか自動判断できず、コンフリクトとして報告してきます。
演習 2:コンフリクトマーカーを読んで手動解消する
コンフリクトが起きたファイルには、特殊なマーカーが挿入されます。
問題: README.md を開くと以下のようになっています。この内容が何を意味するか説明し、"Hello" を採用する形で手動解消してください。
<<<<<<< HEAD
Hello
=======
Hi
>>>>>>> feature/greeting
答えを見る
マーカーの意味を図示します。
<<<<<<< HEAD ← ここから
Hello ← 現在のブランチ(main)側の内容
======= ← 境界線
Hi ← 取り込もうとしたブランチ(feature/greeting)側の内容
>>>>>>> feature/greeting ← ここまで"Hello" を採用する場合、マーカーごと以下のように書き換えます。
Hello解消後、ステージングしてコミットします。
git add README.md
git commit -m "Merge feature/greeting into main(Hello を採用)"git add した時点でコンフリクトが解消済みだと Git に伝わり、git commit でマージコミットが完成します。
演習 3:git mergetool でビジュアルツールを使って解消する
行数が多いファイルや複雑な変更の場合、テキストエディタでの手動解消は大変です。
問題: 設定済みの mergetool を使ってコンフリクトを解消するコマンドを書いてください。
答えを見る
git mergetool事前に使用するツールを設定しておく必要があります。
# 例: VSCode を mergetool として使う
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'git mergetool を実行すると、設定したツール(VSCode の3-way diffビューなど)が開き、「自分の変更」「相手の変更」「結果」を並べて視覚的に比較しながら解消できます。解消後は通常通り git add → git commit で完了します。
演習 4:git merge —abort でマージをキャンセルしてやり直す
マージを始めたものの、コンフリクトが多すぎる、あるいは対応するタイミングではないと気づいた場合を扱います。
問題: 進行中のマージを中断し、マージ開始前の状態に戻すコマンドを書いてください。
答えを見る
git merge --abortgit status で確認すると、マージが開始される前の状態に完全に戻っていることが確認できます。
On branch main
nothing to commit, working tree cleanコンフリクトの数が多く落ち着いて対応できないときや、そもそもタイミングが悪いと感じたときは、無理に解消しようとせず一度 --abort して出直すのも有効な選択肢です。
演習 5:rebase 中のコンフリクトを —continue / —abort で制御する
merge だけでなく、rebase 中にもコンフリクトは発生します。制御方法は似ていますが、コミットのたびに繰り返す点が異なります。
問題: rebase 中にコンフリクトが発生した場合の「解消して次に進む」操作と、「rebase 自体をやめる」操作をそれぞれ書いてください。
答えを見る
# 解消して次のコミットの rebase に進む
git add <解消したファイル>
git rebase --continue
# rebase 自体を中断し、開始前の状態に戻す
git rebase --abortmerge との違いは、rebase は複数のコミットを1つずつ順番に付け替えていくため、コミットの数だけコンフリクトが発生しうる点です。1つ解消しても、次のコミットでまたコンフリクトが起きることがあります。
| 状況 | merge | rebase |
|---|---|---|
| 解消して確定する | git add → git commit | git add → git rebase --continue |
| やめて元に戻す | git merge --abort | git rebase --abort |
まとめ
コンフリクトマーカーの意味を再確認します。
<<<<<<< HEAD 自分(現在のブランチ)の変更
(自分の内容)
======= 境界線
(相手の内容)
>>>>>>> ブランチ名 相手(取り込もうとしたブランチ)の変更
コンフリクトは「どちらが正しいかを Git が判断できない」だけであり、異常事態ではありません。落ち着いてマーカーを読み、必要なら --abort でやり直せることを覚えておけば、恐れる必要はありません。