RebaseとMergeでのコンフリクト解決の違い
git mergeとgit rebaseでのコンフリクトの違いを理解します。リベース中にours/theirsが入れ替わる理由と、連続コンフリクトの処理方法を学びます。
Best Practices
詳細な説明
Rebase vs Merge: コンフリクトの違い
git mergeとgit rebase中のコンフリクトの違いを理解することは極めて重要です。同じファイルでも使用する操作によって異なるコンフリクトパターンが生じる可能性があるためです。さらに重要なのは、リベース中は「ours」と「theirs」の意味が逆転することです。
git merge中
git checkout main
git merge feature
- Ours = main(現在いるブランチ)
- Theirs = feature(マージされるブランチ)
- マージ全体で1回だけコンフリクトを解決します。
git rebase中
git checkout feature
git rebase main
- Ours = main(リベース先のブランチ)— これが入れ替わり!
- Theirs = feature(リプレイされる自分のコミット)
- コンフリクトを複数回解決する必要がある場合があります — リプレイされるコミットごとに1回。
入れ替わりが起きる理由
リベース中、Gitは各コミットをターゲットブランチの上にリプレイします。各リプレイにおいて、ターゲットブランチを「現在の」状態(ours)として、自分のコミットを取り込み変更(theirs)として扱います。これはほとんどの開発者が直感的に期待するものと正反対です。
リベースの連続コンフリクト
ブランチに5つのコミットがあり、そのうち3つがコンフリクトする場合、リベース中に3回別々にコンフリクトを解決します。各解決後、git rebase --continueを実行して次のコミットに進みます。
実践的な考慮事項
| シナリオ | 推奨アプローチ |
|---|---|
| 短期間のfeatureブランチ、コミット少数 | クリーンな履歴のためにmainにリベース |
| 長期間のブランチ、多くのコンフリクトが予想される | 繰り返しの解決を避けるためにマージ |
| 複数の貢献者がいる共有ブランチ | マージ(共有ブランチを絶対にリベースしない) |
| PRレビュー前のクリーンアップ | インタラクティブリベース、その後マージ |
中止とリトライ
リベース中に混乱した場合、いつでもgit rebase --abortで元の状態に戻してやり直すことができます。マージ中はgit merge --abortを使用してください。
ユースケース
10コミットのfeatureブランチを更新されたmainブランチにリベースしていて、複数のコミットでコンフリクトに遭遇します。ours/theirsの入れ替わりを理解することで、各コンフリクトを正しく解決できます。