こんにちは、かつコーチです。
前回はgit mergeの基本を解説しました。
マージを使い始めると、必ずと言っていいほど一度はぶつかるのが「コンフリクト」です。
初めて見ると身構えてしまいますが、仕組みさえ分かれば怖くありません。
今回はコンフリクトが起きる理由と、実際の解決手順を丁寧に見ていきましょう。
コンフリクトとは
2人が同じ行を別々に書き換えた原稿
コンフリクトとは、2人が同じ原稿の同じ行を、別々の内容に書き換えてしまった状態のようなものです。
Aさんが3行目を「明日は晴れです」に書き換え、Bさんが同じ3行目を「明日は雨です」に書き換えたとします。
この2つの下書きを1つの原稿にまとめようとしても、どちらを採用すればいいかは機械的には決められません。
Gitも同じで、同じファイルの同じ箇所に対して、2つのブランチで異なる変更が加えられていると、どちらを正としていいか自動で判断できず、人間に判断を委ねてきます。
これがコンフリクト(衝突)です。
コンフリクトが発生する条件
逆に言えば、次のような場合はコンフリクトになりません。
- 別々のファイルを編集していた
- 同じファイルでも、離れた箇所を編集していた
Gitは行単位で変更を管理しているため、同じ箇所を書き換えていない限り、自動で両方の変更を取り込んでくれます。
コンフリクトは「Gitが壊れた」わけではなく、「本当に人間が判断すべき場面」に差し掛かったというサインだと捉えましょう。
コンフリクトが発生したときの画面を読み解く
<<<<<<< ======= >>>>>>> の意味
実際にコンフリクトが起きると、ファイルの中に次のような記号が挿入されます。
git merge feature-weather
Auto-merging report.txt
CONFLICT (content): Merge conflict in report.txt
Automatic merge failed; fix conflicts and then commit the result.
report.txtを開くと、こうなっています。
<<<<<<< HEAD
明日は晴れです
=======
明日は雨です
>>>>>>> feature-weather
それぞれの記号の意味は次の通りです。
| 記号 | 意味 |
|---|---|
<<<<<<< HEAD | ここから、今いるブランチ(自分側)の内容 |
======= | 境界線 |
>>>>>>> feature-weather | ここまでが、取り込もうとしたブランチ側の内容 |
つまり「上下2つの候補が出ているので、どちらを採用するか(あるいは両方混ぜるか)決めてください」とGitが教えてくれているわけです。
git statusで状況を確認する
コンフリクト中は、git statusでも状態を確認できます。
git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: report.txt
「both modified(両方で修正されている)」という表示が、コンフリクトの対象ファイルです。
複数ファイルでコンフリクトすることもあるので、まずは対象ファイルを一覧で把握しましょう。
コンフリクトを解決する手順
手動で書き換えて解決する
コンフリクトの解決は、基本的にエディタでファイルを直接編集する作業です。
たとえば「晴れの予報が確定情報なので、こちらを採用する」と判断したなら、記号ごと削除して、必要な内容だけを残します。
❌ Before:記号を消し忘れたままファイルが残っている
<<<<<<< HEAD
明日は晴れです
=======
明日は雨です
>>>>>>> feature-weather
このままgit add・git commitしてしまうと、<<<<<<<などの記号がそのままファイルに残ってしまいます。
私も一度、急いで解決した際にこの記号を消し忘れたままコミットしてしまい、後からファイルを開いた同僚に指摘されたことがあります。
✅ After:どちらを採用するか決めて、記号ごときれいに整理する
明日は晴れです
両方の内容を活かしたい場合は、記号を消したうえで両方の文章を残す形でも構いません。
大切なのは、<<<<<<<・=======・>>>>>>>という記号を必ず全部消すことです。
git add → git commitで解決を確定する
ファイルの中身を整理したら、通常のコミットと同じ流れで確定させます。
# 解決したファイルをステージする
git add report.txt
# コミットメッセージはデフォルトのままでもOK
git commit
git addをすることで、Gitに対して「このファイルのコンフリクトは解決済みです」と伝えられます。
コミットメッセージは、エディタが自動で「Merge branch ‘feature-weather’ into main」のような内容を用意してくれるので、そのまま保存すれば完了です。
よくあるつまずきポイント
コンフリクトマーカーを消し忘れてコミットしてしまう
先ほども触れましたが、記号の消し忘れは非常によくある失敗です。
コミット前に、必ず対象ファイルを開いて<<<<<<<が残っていないか目視確認する習慣をつけましょう。
慣れないうちは、コミット直前に次のコマンドで記号が残っていないかを検索するのもおすすめです。
grep -rn "<<<<<<<" .
何も表示されなければ、消し忘れはありません。
VSCodeなどのマージエディタを使う
手動でのテキスト編集に慣れるまでは、エディタのマージ機能を使うと格段に楽になります。
VSCodeの場合、コンフリクトが起きたファイルを開くと「Accept Current Change」「Accept Incoming Change」「Accept Both Changes」といったボタンが表示され、クリックひとつで記号ごと整理してくれます。
コマンドラインでの解決に慣れるまでは、こうした支援機能に頼るのも良い選択です。
応用・一歩先の使い方
コンフリクトを未然に防ぐ工夫
コンフリクトを完全にゼロにすることはできませんが、頻度を減らす工夫はあります。
- こまめにmainの変更を自分のブランチに取り込んでおく(
git merge mainやgit pull) - ブランチを長期間放置せず、小さく分けて早めにマージする
- 同じファイルを複数人が同時に触る作業は、事前にチーム内で調整する
「差分が小さいうちにこまめに合流させる」ことが、コンフリクト対策の基本方針です。
git merge –abortでやり直す
コンフリクトの内容が複雑すぎて「一旦やめて考え直したい」というときは、マージ自体を中断できます。
git merge --abort
これでマージ前の状態に戻るので、落ち着いてから改めてマージに挑戦しましょう。
まとめ
この記事のポイント
- コンフリクトは「2人が同じ行を別々に書き換えた原稿」のような状態で、Gitが自動で決められないときに発生する
<<<<<<< HEAD〜=======〜>>>>>>>の記号で、どちらの変更が候補かを確認できる- 解決は「ファイルを手動編集→記号を全部消す→
git add→git commit」という流れ - 記号の消し忘れに注意し、コミット前に必ず目視確認する
- こまめなマージでコンフリクトの頻度自体を減らせる
次に読むべき記事
マージやコンフリクトを経験したら、次は履歴を操作するgit resetとgit revertの違いを押さえておきましょう。
→ 次の記事:git resetとgit revertの違い
タグ: Git, 中級者向け, ブランチ