コンフリクトが起きた原因
個人開発中の業務システムで、在庫管理のための「品目マスタ機能」(扱う原材料や資材の情報を登録・管理する機能)のブランチを切って作業を進めていました。しかしこのブランチは、当時自作していたログイン機能をベースに派生させたものでした。
その後、ログイン機能を作り直すために新しくブランチを切って作業し、そちらをmainに取り込んだため、次のような状態になっていました。
-
mainブランチ:新しいログイン機能 -
品目マスタブランチ:古い(自作の)ログイン機能 + 品目マスタの実装
この状態で品目マスタブランチをmainにマージしようとした結果、ログイン機能に関連するファイルで内容が競合し、コンフリクトが発生しました。
同じファイルを別々の内容で変更したブランチ同士をマージすると、Gitはどちらを採用すべきか判断できずコンフリクトマーカー(<<<<<<<、=======、>>>>>>>)を挿入して人間の判断を求めてきます。今回はまさにこのケースでした。
解消までの試行錯誤
正直なところ、コンフリクト解消は自分にとって苦手意識のある作業でした。コンフリクトマーカーを見て、どの範囲がどちらのブランチ由来のコードで、最終的にどちらを採用すべきかは把握できていました。ただ、それを実際にどう解消すればいいのか、具体的な手順が分かりませんでした。
VSCodeにマージエディタ機能があることはこの時知らず、エディタ上のコンフリクトマーカーを直接見ながら対応することになりました。最終的にはAIに相談しながら解消を進めましたが、正直なところ「なぜその方法で解決したのか」を完全に理解しないまま作業を終えてしまった部分もあります。この記事はその反省も込めて書いています。
解決方法
今回はgit checkout --ours(または--theirs)を使って、片方のブランチの内容を採用する形で解消しました。
# コンフリクトが起きているファイルに対して、
# 自分がマージ先にいるブランチ側の内容を採用する場合
git checkout --ours <ファイルパス>
# マージしようとしている側(取り込む側)の内容を採用する場合
git checkout --theirs <ファイルパス>
# 採用後はステージングして完了
git add <ファイルパス>
git commit
ここで注意したいのは、--oursと--theirsの意味はマージの方向によって変わるという点です。
- 通常の
git merge実行時:--ours=今いるブランチ(マージ先)、--theirs=取り込むブランチ -
git rebase実行時:意味が逆転する
学んだこと・注意点
-
--ours/--theirsは「片方を丸ごと採用する」コマンドであり、両方の変更を活かしたい場合には不向き。今回はログイン機能を丸ごと新しい方に統一したかったので結果的に噛み合いましたが、部分的に両方の変更を残したい場面では手動でのコード統合が必要になる。 - VSCodeのマージエディタ機能を知らなかった。次回からはコンフリクトマーカーを目視するだけでなく、こうした支援機能も選択肢に入れたい。
-
コンフリクトの根本原因はブランチ戦略にあることが多いと思う。今回のケースも、ログイン機能という土台部分を別ブランチで作り直している間、すでにそこから派生していた
品目マスタブランチとの整合性を意識できていれば防げた可能性がある。
まとめ
コンフリクトは実際の開発現場でも起こり得るものなので、いざという時に解消できるようにしておく必要があると感じました。また、たとえ解消できたとしても、マージの方向(--ours/--theirsがそれぞれ何を指すか)を理解しないまま作業してしまうと、意図しない修正を紛れ込ませてしまう可能性があります。解消の手順を知っているだけでなく、その裏側の意味まで理解しておくことが大切だと学びました。