Git のコンフリクトとは?解消のしかた・やめて戻す方法(--abort)・GitHub の画面で解く

PR
Git のコンフリクトとは?解消のしかた・やめて戻す方法(--abort)・GitHub の画面で解く
この記事は約40分で読めます。

Git のコンフリクト(競合)は、マージなどで、同じ場所に別々の変更があり、Git がどちらを残すか決められないときに起きます。Git はそこで止まり、ぶつかった所に印(マーカー)を書き込みます。あとは、人が残す中身を決めて直し、git add で「解いた」と伝えて続けるか、--abort でやめて、始める前の状態に戻すかのどちらかです(戻らないものもあります。あとで説明します)。

ただし、同じ印でも、merge・rebase・cherry-pick・stash pop・pull で、起き方・やめ方・「どちらが自分の側か」が違います。とくに印の上半分は、いつも自分の側とは限りません。この記事は、初心者の方に向けて、公式の文書に沿って、その違いと、GitHub の画面で解く方法をまとめたものです。

コマンドの出力は git 2.39.3(Apple Git-145・macOS)のものです(2026年10月時点の最新は 2.56.0 です)。Git の表示は英語で出ます。ハッシュ(コミットの名前になる英数字)は例で、読者の手元では違う値になります。

この記事でわかること
  • コンフリクトとは何か、どんなときに起きるか(merge 以外でも起きる)
  • ぶつかったファイルの見つけ方と、マーカーの読み方(HEAD がどちらの側か)
  • merge でのコンフリクトの解消の手順と、マーカーを消し忘れたときの確かめ方
  • --abort でやめて元に戻す方法と、戻らないもの
  • 片方の側を丸ごと選ぶ --ours・--theirs と、rebase で向きが逆になること
  • GitHub の画面で解く手順と、解けないとき
  1. コンフリクトとは?どんなときに起きる?
  2. コンフリクトが起きたら?ぶつかったファイルとマーカーの読み方
    1. 起きたときの表示
    2. どのファイルがぶつかったか(git status)
    3. マーカーの読み方:HEAD はどちらの側?
    4. 元の中身も出したいとき(diff3・zdiff3)
  3. コンフリクトを解くには?(merge の手順)
    1. 手順
    2. マーカーを消し忘れていないか確かめるには?
    3. 解くときに使える道具
    4. 片方が消し、片方が書き換えたとき
  4. やめて元に戻すには?(--abort)
    1. 場面ごとのやめ方
  5. 片方の側を丸ごと選ぶには?(--ours・--theirs)
    1. バイナリのファイルがぶつかったとき
    2. 選び直したいとき
    3. -X ours と -s ours はまったく別もの
  6. rebase・cherry-pick・stash pop・pull でコンフリクトしたら?
    1. rebase でコンフリクトしたら(ours と theirs が逆になる)
    2. cherry-pick でコンフリクトしたら
    3. stash pop でコンフリクトしたら(--abort は無い)
    4. pull でコンフリクトしたら
    5. 早見:場面ごとの違い
  7. GitHub の画面や VS Code で解くには?
    1. GitHub のプルリクエストの画面で解く
    2. VS Code で解く
  8. よくある質問
    1. マーカーの HEAD は、上と下のどちらが自分の側?
    2. git merge --abort で「MERGE_HEAD missing」と出るのは?
    3. GitHub で「Resolve conflicts」が押せないのは?
    4. コンフリクトの解き方を間違えたら、やり直せる?
  9. まとめ
  10. 参考資料

コンフリクトとは?どんなときに起きる?

Git は、ブランチ(作業の枝分かれ)どうしの違いを、たいてい自動でマージ(合流)できます。ふつうは変更が別の行や別のファイルにあるので、多くの場合は人の手は要りません(GitHub の文書)。ただし、手元の git 2.39.3 では、隣り合った行を変えただけでもコンフリクトになりました。人の手が要るのは、競合する変更があるときです。GitHub の文書は、コンフリクトがよく起きる場面として、次の2つを挙げています。

  • 同じファイルの同じ行を、別々の人(別々のブランチ)が変えたとき
  • 一方がファイルを書き換え、もう一方が同じファイルを消したとき

共通の元から、片方だけが変えた所は、そのまま結果に入ります。止まるのは、両方が同じ所を変えたときです。Git はどちらかを勝手に選べないので、人に解いてもらいます。コンフリクトを解くとは、マージのあとに残す最終の中身を決めることです。

コンフリクトは、merge だけでなく、rebase・cherry-pick・revert・stash pop(apply)でも起きます。

  • merge: 別のブランチの変更を、いまのブランチに合流させる。違いは Git MergeとRebaseの違いの記事でも説明しています
  • rebase: 自分のコミットを、別のブランチの先に載せ直す
  • cherry-pick: 指定したコミットの変更だけを、いまのブランチに当てる
  • stash pop: しまっておいた変更(stash)を戻す。git stash の使い方の記事で説明しています

git pull は、リモートの変更を取ってくる(fetch)あとで、merge か rebase を動かします。なので、pull のコンフリクトは、merge か rebase のコンフリクトです。

GitHub のプルリクエスト(変更を取り込んでもらう依頼)では、コンフリクトを全部解くまでマージできません。コンフリクトがある間は、Merge pull request のボタンが押せなくなります。コマンドで merge したときも、解いてコミットするまで、マージの結果は push できません。プルリクエストの基本はプルリクエストとは?の記事にあります。

コンフリクトが起きたら?ぶつかったファイルとマーカーの読み方

起きたときの表示

例として、a.txt(3行)があり、feature ブランチと main ブランチで、2行目を別々に変えてコミットした場面を使います。main にいる状態で、git merge feature を流しました(git 2.39.3 の出力)。

$ git log --oneline --graph --all
* e18383c feature: change line2
| * 2f798fd main: change line2
|/
* 3652f75 first
$ git merge feature
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.

「CONFLICT」の行が、どのファイルでぶつかったかを教えてくれます。終了コードは 1 で、マージのコミットはまだ作られていません。Pro Git(英語)は、Git がマージのコミットを自動では作らず、コンフリクトを解く間、処理を止めている、と説明しています。

止まっている間の状態は、git-merge の文書によると、次のとおりです。

  • HEAD(いま作業しているブランチを指す名前。ふつうはそのブランチの最新のコミットを指す。rebase の途中などは、ブランチではなくコミットを直接指す。detached HEAD と呼ぶ)は動かない
  • MERGE_HEAD が、取り込もうとした相手のブランチの先を指す
  • ぶつからなかったファイルは、もうインデックス(git add した状態を置く場所)と作業ツリー(手元のファイル)に入っている
  • マージの前の、いまのブランチの先は ORIG_HEAD に入る

どのファイルがぶつかったか(git status)

git status で、ぶつかったファイルが分かります。「Unmerged paths:」(まだマージできていないファイル)の下に「both modified:」と出ます。git 2.39.3 の status は、やめ方(git merge --abort)と、解いたあとの印の付け方(git add <file>...)も案内してくれます。

$ git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   a.txt

no changes added to commit (use "git add" and/or "git commit -a")

短い表示の git status --short では、ぶつかったファイルに2文字の印が付きます。この例では UU a.txt(両方が変えた)です。公式の文書にある印は、次の7つです。

印意味
UU両方が変えた
AA両方が足した
DD両方が消した
AU自分の側が足した
UA相手の側が足した
DU自分の側が消した
UD相手の側が消した

ぶつかったファイルは、インデックスに最大3つの版が入ります。1番が共通の元、2番が HEAD(自分)、3番が MERGE_HEAD(相手)です。git ls-files -u で一覧でき、git show :1:a.txt(元)・git show :2:a.txt(HEAD)・git show :3:a.txt(MERGE_HEAD)で、それぞれの中身を出せます。

$ git ls-files -u
100644 83db48f84ec878fbfb30b46d16630e944e34f205 1	a.txt
100644 b0db2f82cef62b2e887c2bb1df77bf8d389d1de7 2	a.txt
100644 a31402d24bb009cbe8402609ef57a471a5736d82 3	a.txt
$ git show :2:a.txt
line1
main line2
line3

マーカーの読み方:HEAD はどちらの側?

ぶつかったファイルを開くと、ぶつかった所が <<<<<<<・=======・>>>>>>> の3つの印(マーカー)で囲まれています。

line1
<<<<<<< HEAD
main line2
=======
feature line2
>>>>>>> feature
line3

git-merge の文書では、======= より上がふつうは自分の側、下が相手の側です。merge のときは、<<<<<<< HEAD から ======= までが、HEAD、つまり merge を実行したときにいたブランチ(この例では main)の中身です。======= から >>>>>>> feature までが、取り込もうとしたブランチ(feature)の中身です。

注意: 「上半分がいつも自分の側」ではありません。rebase と git pull --rebase では、<<<<<<< HEAD の側は、自分のブランチではなく、上に載せる先(たとえば main)です。>>>>>>> の側が、載せ直している自分のコミットです。merge と上下の意味が逆に見えるので、あとの「rebase でコンフリクトしたら」で説明します。

>>>>>>> のうしろの名前も、場面で変わります(git 2.39.3 の出力)。

場面上の印のうしろ下の印のうしろ
mergeHEADブランチの名前(例 feature)
pull(merge)HEADコミットの40桁の名前
rebase・cherry-pickHEAD当てようとしたコミット(例 e18383c (feature: change line2))
stash popUpdated upstreamStashed changes
git restore --merge で作り直したときourstheirs

元の中身も出したいとき(diff3・zdiff3)

既定の書き方は、ぶつかった所の「元の中身」を出しません。設定の merge.conflictStyle を diff3 か zdiff3 にすると、||||||| の印のあとに元の中身も出ます。元を見ると、よい解き方が分かることがあります、と git-merge の文書は書いています。手元では、そのリポジトリだけに設定して流しました(git 2.39.3 の出力)。

$ git config merge.conflictStyle diff3
$ git merge feature
(省略)
$ cat a.txt
line1
<<<<<<< HEAD
main line2
||||||| 3652f75
line2
=======
feature line2
>>>>>>> feature
line3

||||||| の下の line2 が、共通の元の中身です。zdiff3 は diff3 に近く、ぶつかった所の頭と終わりで、両方が同じになっている行を、囲みの外に出します(2.35 で入りました)。この例では頭と終わりに同じ行が無いので、diff3 と同じ表示になりました。Pro Git の例は git config --global merge.conflictstyle diff3 で、--global を付けると、すべてのリポジトリに効きます。

コンフリクトを解くには?(merge の手順)

コンフリクトを見たら、できることは2つです。マージをやめる(git merge --abort。あとの節で説明します)か、解くかです。解くときは、ファイルを直して git add し、git commit か git merge --continue で終えます。--continue は、途中のマージがあるかを確かめてから git commit を呼ぶ、と git-merge の文書にあります。

手順

  1. git status で、ぶつかったファイルを確かめる
  2. エディタでファイルを開き、<<<<<<< を探して直す
  3. 直したファイルを git add する
  4. git commit か git merge --continue で、マージを終える

直し方は3通りです。自分の側だけ残す、相手の側だけ残す、両方を合わせた新しい中身にする。どれでも、マーカーの3行(<<<<<<<・=======・>>>>>>>)は消します。ここでは、両方を合わせて、2行目を main and feature line2 にしました。

line1
main and feature line2
line3

直したファイルを git add すると、「解いた」印になります。全部 add すると、status は「All conflicts fixed but you are still merging.」と出ます。まだマージの途中で、コミットが残っているという意味です(git 2.39.3 の出力)。

$ git add a.txt
$ git status
On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
	modified:   a.txt

$ git merge --continue
[main 0bf5a29] Merge branch 'feature'
$ git log --oneline --graph
*   0bf5a29 Merge branch 'feature'
|\
| * e18383c feature: change line2
* | 2f798fd main: change line2
|/
* 3652f75 first

マージのコミットのメッセージは、何も書かなければ「Merge branch 'feature'」になりました(手元で、エディタを開かない設定で流したときの結果です)。

まだ add していないファイルがあるうちは、git commit も git merge --continue も止まります(終了コード 128)。

$ git commit -m "try"
error: Committing is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
U	a.txt

GitHub の文書の手順は、直したあとに git add . と git commit -m "…" です。ただし、git add . のようにフォルダを渡すと、そのフォルダの中の変更(関係ないファイルの書き換えや、新しいファイルも)を全部 add します。この記事の例は、git add a.txt のように、ファイルを名指しにして流しました。

マーカーを消し忘れていないか確かめるには?

注意: マーカーを消し忘れたままでも、手元の git 2.39.3 では、git add も git commit も止まりませんでした。マーカー入りのファイルが、そのままコミットされます。

消し忘れは git diff --check で見つかります。「leftover conflict marker」(消し忘れたマーカー)と知らせてくれます。add の前は git diff --check、add のあとは git diff --cached --check です。見つけると終了コードは 2 になります(git 2.39.3 の出力)。

$ git diff --check
a.txt:2: leftover conflict marker
a.txt:4: leftover conflict marker
a.txt:6: leftover conflict marker
$ git add a.txt
$ git diff --cached --check
a.txt:2: leftover conflict marker
a.txt:4: leftover conflict marker
a.txt:6: leftover conflict marker

新しい版には、消し忘れたファイルを add しないオプションがあります。Git 2.56.0(2026年9月28日公開)の文書によると、git add --resolved は、ぶつかっていたファイルのうち、マーカーが残っていないものだけを「解いた」として add します。マーカーが1つでも残っているファイルがあると、どのファイルも add しません。関係ないローカルの変更は add しません。手元の 2.39.3 にはこのオプションが無いので、流しておらず、止まったときの表示は確かめていません。

解くときに使える道具

git-merge の文書にある道具です。

  • git diff: HEAD と MERGE_HEAD の両方からの変更を、3方向で出す
  • git diff AUTO_MERGE: ここまでに自分が直した分を出す。AUTO_MERGE は、既定の ort(2.34 から既定になったマージのやり方)でマージしたときだけ作られる
  • git log --merge -p <path>: ぶつかったファイルを触ったコミットの差分を出す
  • git mergetool: 画面のあるマージの道具を開く。Pro Git によると、道具を選んで開き、ぶつかった所を順に案内する(手元では流していません)

手で解くのが難しいときは、Pro Git が勧めるように、ぶつかった2つの側のコミットを見ると、なぜ同じ所を触ったかを思い出す手がかりになることがあります。

$ git log --merge --oneline --left-right
< 2f798fd main: change line2
> e18383c feature: change line2

片方が消し、片方が書き換えたとき

一方がファイルを書き換え、もう一方が消したときも、コンフリクトになります。feature で a.txt を書き換え、main で a.txt を消してあるとき、main で git merge feature を流すと、次のように出ました(git 2.39.3 の出力)。

$ git merge feature
CONFLICT (modify/delete): a.txt deleted in HEAD and modified in feature.  Version feature of a.txt left in tree.
Automatic merge failed; fix conflicts and then commit the result.
$ git status --short
DU a.txt

git status は「deleted by us:」(自分の側が消した)と出し、作業ツリーには書き換えた側のファイルが残ります。マーカーは入りません。ファイルを残すなら git add <ファイル>、消すなら git rm <ファイル> をして、コミットします(GitHub の文書の手順です)。手元では、git rm a.txt ではファイルが消えたマージのコミットになり、git add a.txt では feature の中身で残りました。

やめて元に戻すには?(--abort)

解くのが難しいときや、予想していなかったコンフリクトのときは、いったんやめられます。git merge --abort は、いまのコンフリクトの解きかけをやめて、マージの前の状態に戻そうとします(git-merge の文書)。手元では、status が「nothing to commit, working tree clean」に戻り、HEAD もマージの前のコミットのままでした(git 2.39.3 の出力)。

$ git merge --abort
$ git status
On branch main
nothing to commit, working tree clean
$ git log --oneline -1
2f798fd main: change line2

注意: --abort は、解きかけた中身を捨てます。手で直した分も、git add した分も、マージの前に戻ります。手元でも、直しかけて add しないまま --abort したときも、add したあとに --abort したときも、a.txt は main line2 の元の中身に戻りました。VS Code の文書も「中止すると、コンフリクトを解いた作業は消える。残したい編集は先にコピーする」と注意しています。

もう1つ注意: マージを始めたときに、コミットしていない変更があると、--abort でもその変更を元どおりにできないことがあります、と git-merge の文書は書いています。そのため、merge の前に、変更をコミットするか stash(しまっておく)しておくよう勧めています。文書は「コミットしていない込み入った変更があるまま merge するのは勧めない」とも書いています。手元の git 2.39.3 では、マージと関係ないファイルの未コミットの変更は、--abort のあとも残りました。「できないことがある」場面は流していません。stash は git stash の使い方の記事で説明しています。

そもそも、merge や pull は、コミットしていない変更が、書き換えるファイルと重なると、何もせずに止まります。インデックスに HEAD とちがう変更(git add した変更)があるときも、関係ないファイルでも止まります。手元の git 2.39.3 では、次のように出ました(終了コード 2)。この場合はコンフリクトの前なので、--abort は要りません。変更をコミットするか stash してから、もう一度 merge します。

$ git merge feature
error: Your local changes to the following files would be overwritten by merge:
	a.txt
Please commit your changes or stash them before you merge.
Aborting
Merge with strategy ort failed.

マージの途中でないときに git merge --abort を打つと、次のように止まります(終了コード 128)。手元の git 2.39.3 では、stash pop・rebase・cherry-pick のコンフリクトの途中でも、マージではないので、これが出ました。

$ git merge --abort
fatal: There is no merge to abort (MERGE_HEAD missing).

ほかのやめ方もあります。

  • git merge --quit: マージをやめたことにするが、インデックスと作業ツリーはそのまま残す。--abort と違って、元に戻さない
  • git reset --hard HEAD: Pro Git によると、これでも最後のコミットの状態に戻り、やり直せる。ただし、コミットしていない作業は全部消えます。reset はGit で取り消すには?の記事で説明しています

git-merge の文書によると、git merge --abort は、MERGE_HEAD があるとき、git reset --merge と同じです(merge の前の自動の stash があるときを除く)。

場面ごとのやめ方

やめ方は、起こした操作ごとに違います。

場面やめるコマンド
mergegit merge --abort
rebasegit rebase --abort(ブランチを rebase の前に戻す)
cherry-pickgit cherry-pick --abort(始める前の状態に戻す。文書の例では、作業ツリーにあったローカルの変更は残る)
revertgit revert --abort(Git で取り消すには?の記事)
pullpull の中で動いたほうに合わせて、git merge --abort か git rebase --abort
stash pop--abort は無い(あとの節で説明します)

なお、VS Code の「中止」のコマンド(Git: Abort Merge など)は、stash を戻した操作は取り消しません。

片方の側を丸ごと選ぶには?(--ours・--theirs)

ぶつかったファイルを、片方の側の中身で丸ごと置き換えることもできます。git checkout --ours <ファイル> は自分の側(インデックスの2番)、git checkout --theirs <ファイル> は相手の側(3番)の中身にします。git restore --ours と --theirs も同じです。Pro Git は、片方を選ぶだけでよいときにすばやい方法で、とくに画像などのバイナリのファイルのコンフリクトで役に立つ、と書いています。

merge のときは、ours がいまのブランチ(HEAD の側)、theirs が取り込むブランチです。この例では、--ours で main の行、--theirs で feature の行になりました(git 2.39.3 の出力)。

$ git checkout --ours a.txt
Updated 1 path from the index
$ cat a.txt
line1
main line2
line3
$ git checkout --theirs a.txt
Updated 1 path from the index
$ cat a.txt
line1
feature line2
line3

注意: --ours と --theirs は、ファイルの中身を置き換えるだけで、「解いた」印は付きません。手元の git 2.39.3 では、--ours のあとも、git status --short は UU のままでした。選んだら、git add <ファイル> をして、git commit で終えます。

$ git checkout --theirs a.txt
Updated 1 path from the index
$ git add a.txt
$ git commit --no-edit
[main ab1e108] Merge branch 'feature'

ぶつかったファイルは、何も付けない git checkout <ファイル> や git restore <ファイル> では戻せません。「error: path 'a.txt' is unmerged」と出て、終了コード 1 で止まります。文書によると、add して解いた印を付けるまでは失敗します。-f で無視するか、--ours・--theirs で片方を採るか、-m で元のコンフリクトの結果に戻します。

バイナリのファイルがぶつかったとき

画像などのバイナリのファイルがぶつかると、手元の git 2.39.3 では「warning: Cannot merge binary files: img.bin (HEAD vs. feature)」と出ました。作業ツリーには HEAD の側の中身が残り、マーカーは入りません。git checkout --theirs img.bin で、相手の中身になりました。

選び直したいとき

git restore --merge <ファイル>(git checkout -m <ファイル> でも同じ)で、マーカーの入ったコンフリクトの状態を作り直せます。--conflict=diff3 や --conflict=zdiff3 を付けると、元の中身も出る形で作り直します。作り直したマーカーは、HEAD や feature ではなく ours と theirs の名前になります(git 2.39.3 の出力)。

$ git restore --merge a.txt
$ cat a.txt
line1
<<<<<<< ours
main line2
=======
feature line2
>>>>>>> theirs
line3

手元の git 2.39.3 では、--theirs を選んで git add したあと(コミットの前)でも、git restore --merge で UU のコンフリクトの状態に戻せました。コミットのあとは試していません。

-X ours と -s ours はまったく別もの

マージのときに、ぶつかった所だけを自動で片方に寄せるオプションもあります。-X ours(-X theirs)です。ぶつからない相手の変更は、そのまま入ります。

注意: -X ours と、-s ours を取り違えないでください。-s ours は、相手のしたことを全部捨てる、別のやり方です。git-merge の文書は、相手の中身を一切見ず、「自分の履歴に、相手で起きたことのすべてが含まれている」と宣言する、と説明しています。-s theirs というやり方は、ありません。

書き方起きること
git merge -X ours featureぶつかった所だけ、自分の側にする。ぶつからない相手の変更は入る
git merge -X theirs featureぶつかった所だけ、相手の側にする。ぶつからない相手の変更は入る
git merge -s ours feature相手の変更は、ぶつからないものも含めて全部入らない

手元では、feature に、ぶつからない b.txt を足すコミットを1つ足して比べました(git 2.39.3)。-X theirs では a.txt が feature の行になり、b.txt も入りました。-X ours では a.txt は main の行のままで、b.txt は入りました。-s ours では、「Merge made by the 'ours' strategy.」と出て、b.txt は入りませんでした。

注意: rebase の途中では、ours と theirs が逆になります。次の節で説明します。

rebase・cherry-pick・stash pop・pull でコンフリクトしたら?

ここまでは merge の話でした。rebase・cherry-pick・stash pop・pull では、起き方、やめ方、そして ours と theirs の向きが違います。

rebase でコンフリクトしたら(ours と theirs が逆になる)

rebase は、自分のコミットを1つずつ載せ直します。ぶつかった最初のコミットで止まり、マーカーを残します。feature にいて git rebase main を流すと、次のようになりました(git 2.39.3 の出力)。端末では進み具合の表示(Rebasing (1/1))が別の行に上書きされて見えないので、この表示と、その前後の空の行は、ここでは省いています。

$ git rebase main
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
error: could not apply e18383c... feature: change line2
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply e18383c... feature: change line2
$ git status
interactive rebase in progress; onto 2f798fd
Last command done (1 command done):
   pick e18383c feature: change line2
No commands remaining.
You are currently rebasing branch 'feature' on '2f798fd'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   a.txt

no changes added to commit (use "git add" and/or "git commit -a")

手元の git 2.39.3 の status は、ふつうの git rebase main でも「interactive rebase in progress」と出ました。やめ方(--abort)、飛ばし方(--skip)、続け方(--continue)も案内してくれます。

ファイルを開くと、マーカーは次のようになっています。

line1
<<<<<<< HEAD
main line2
=======
feature line2
>>>>>>> e18383c (feature: change line2)
line3

注意: <<<<<<< HEAD の下にあるのは、自分のブランチ(feature)ではなく、載せる先の main の行です。>>>>>>> の側が、載せ直している自分のコミット(feature の行)です。git-rebase の文書は、「ours と報告される側は、<upstream> から始まる、ここまでに載せ直した列で、theirs は作業中のブランチ。つまり、両者は入れ替わっている」と説明しています。

--ours と --theirs も同じ向きで入れ替わります。git rebase と git pull --rebase の途中では、--ours は載せる先(例: main、リモートの側)、--theirs は載せ直している自分の作業です(git-checkout の文書)。手元でも、--ours で main の行、--theirs で feature の行になりました。

$ git checkout --ours a.txt
Updated 1 path from the index
$ cat a.txt
line1
main line2
line3
$ git checkout --theirs a.txt
Updated 1 path from the index
$ cat a.txt
line1
feature line2
line3

git-checkout の文書は、逆になる理由を、こう説明しています。rebase は、リモートの履歴をみんなの正本とみなし、rebase する自分のブランチの作業を、そこへ取り込む「他の人の作業」として扱う。rebase の間は、自分が正本の番人の役になるため、という説明です。rebase の -X ours・-X theirs も、同じように逆になります(手元では流していません)。VS Code の文書も、名前で選ばず、中身を見て選ぶよう勧めています。

直し方は merge と同じです。ファイルを直して git add し、全部解いたら git rebase --continue です。add する前に --continue を打つと、「a.txt: needs merge」と出て止まります(終了コード 1)。

$ git rebase --continue
a.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add
$ git add a.txt
$ git rebase --continue
[detached HEAD bd1ab56] feature: change line2
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/feature.

rebase はコミットを1つずつ載せ直すので、コミットが複数あると、--continue のあとにまた別のコミットで止まることがあります(VS Code の文書)。止まったら、また直して、rebase が終わるまで繰り返します。手元では1コミットだけで流したので、複数で止まる場面は流していません。

やめるなら git rebase --abort です。手元では、--abort のあと、git log が rebase の前と同じになりました。そのコミットを飛ばすなら git rebase --skip です。飛ばしたコミットの変更は入りません。 手元では、--skip のあと、feature: change line2 のコミットは消え、feature は main と同じ位置になりました。

rebase をしたあと、もう push してあったブランチを push し直すと、強制 push が要ります。強制 push の注意はGit で取り消すには?の記事に、GitHub の Rebase and merge の前に手元で rebase して強制 push することがある話はプルリクエストとは?の記事にあります。

cherry-pick でコンフリクトしたら

git cherry-pick は、指定したコミットの変更を、いまのブランチに当てます。作業ツリーがきれい(HEAD から変更が無い)なことが要ります。当てられないときは、ブランチと HEAD は最後にうまくいったコミットのままで、CHERRY_PICK_HEAD が当てようとしたコミットを指し、ぶつかったファイルにマーカーが入ります。main で git cherry-pick feature を流しました(git 2.39.3 の出力)。

$ git cherry-pick feature
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
error: could not apply e18383c... feature: change line2
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".

マーカーは、<<<<<<< HEAD の下がいまのブランチ、>>>>>>> e18383c (feature: change line2) の上が当てるコミットの中身でした。直して git add し、git cherry-pick --continue で新しいコミットができます。飛ばすなら --skip、やめるなら --abort で、--abort のあとは始める前の状態に戻りました。--quit は、進行中の状態を忘れるだけです。

stash pop でコンフリクトしたら(--abort は無い)

git stash pop で戻す変更が、いまの変更とぶつかると、コンフリクトになります。git-stash の文書によると、このとき stash は一覧から消えません。手で直したあと、自分で git stash drop します。終了コードは 1 です。マーカーは <<<<<<< Updated upstream(いまのブランチの側)と >>>>>>> Stashed changes(stash の側)です(git 2.39.3 の出力)。

$ git stash pop
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
On branch main
Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   a.txt

no changes added to commit (use "git add" and/or "git commit -a")
The stash entry is kept in case you need it again.
$ cat a.txt
line1
<<<<<<< Updated upstream
main line2 v2
=======
stash line2
>>>>>>> Stashed changes
line3

stash のコンフリクトは、解いてもマージのコミットは要りません(VS Code の文書)。手元の status にも、merge のときの「fix conflicts and run "git commit"」や --abort の案内は出ませんでした。

stash pop には --abort がありません。 手元の git 2.39.3 では、git stash pop --abort は「error: unknown option」で始まるエラーになり(終了コード 129)、git merge --abort も前に見た「MERGE_HEAD missing」で止まります。stash は一覧に残るので、中身はなくなりません。

$ git stash pop --abort
error: unknown option `abort'
usage: git stash pop [--index] [-q | --quiet] [<stash>]

    -q, --quiet           be quiet, only report errors
    --index               attempt to recreate the index

$ git stash list
stash@{0}: On main: wip

pop する前の状態に戻したいときは、手元の git 2.39.3 では、git restore --source=HEAD --staged --worktree a.txt で、そのファイルを pop の前(HEAD)の中身に戻せました。stash は残ったままです。これは公式の文書の手順ではなく、手元で出た結果です。 戻るのは、名指ししたファイルだけです。stash にぶつからないファイル(b.txt)も入っていると、pop でそのまま入った b.txt の変更は、add された状態(M b.txt)で残りました。pop の前から stash の外にあった、コミットしていない変更が無事かどうかは試していません。stash の使い方はgit stash の使い方の記事にあります。

pull でコンフリクトしたら

git pull は、リモートから取ってきたあとで、merge か rebase で取り込みます。手元とリモートが分かれていて、同じ行を変えていると、そこでコンフリクトします。git pull --no-rebase なら merge の、git pull --rebase なら rebase のコンフリクトです。

手元の git 2.39.3 では、分かれたブランチで、設定も付けずに git pull すると、コンフリクトの前に「fatal: Need to specify how to reconcile divergent branches.」で止まりました(終了コード 128。取ってくる処理は済んでいます)。最新の文書は、--ff-only(fast-forward だけ。ブランチの先を進めるだけで済む取り込みのことで、分かれていると失敗する)が既定と書いています。どう取り込むかの設定は、git pull と fetch の記事で説明しています。

--no-rebase のときは、merge のコンフリクトです。<<<<<<< HEAD の下が手元の行、>>>>>>> のうしろはリモートのコミットの40桁の名前でした。

$ git pull --no-rebase
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.
$ cat a.txt
line1
<<<<<<< HEAD
alice line2
=======
bob line2
>>>>>>> 5f7812292ce04aae9ce9764e81ba8652f1ba3c7e
line3

--rebase のときは、rebase のコンフリクトで、向きが逆です。この例では、<<<<<<< HEAD の下がリモート(bob)の行で、>>>>>>> の側が自分(alice)のコミットでした。

$ git pull --rebase
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
error: could not apply 18897dd... alice: line2
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 18897dd... alice: line2
$ cat a.txt
line1
<<<<<<< HEAD
bob line2
=======
alice line2
>>>>>>> 18897dd (alice: line2)
line3

pull のコンフリクトをやめるときは、pull の中で動いたほうに合わせて、git merge --abort か git rebase --abort です。手元でも、どちらも pull の前に戻りました。

早見:場面ごとの違い

場面<<<<<<< の側(上)>>>>>>> の側(下)--ours / --theirs解いたあとやめるとき
mergeHEAD=いまいるブランチ取り込むブランチours=いまのブランチ、theirs=取り込むブランチgit add のあと git commit か git merge --continuegit merge --abort
pull(merge)手元のブランチリモートのコミット(名前は40桁)merge と同じmerge と同じgit merge --abort
rebase・pull --rebase載せる先(main・リモート)載せ直している自分のコミット逆: ours=載せる先、theirs=自分の作業git add のあと git rebase --continue。また止まることがあるgit rebase --abort(飛ばすなら --skip)
cherry-pickHEAD=いまのブランチ当てるコミット調べていないgit add のあと git cherry-pick --continuegit cherry-pick --abort
stash popUpdated upstream=いまの側Stashed changes=stash の側調べていない直して git add、git stash drop。マージのコミットは要らない--abort は無い。stash は残る

GitHub の画面や VS Code で解くには?

手元のコマンドのほかに、GitHub の画面(ブラウザー)や、エディターの VS Code でも解けます。ここは、公式の文書の範囲です。GitHub の画面と VS Code は、この記事を書くときに手元で開いていないので、画面の見た目は確かめていません。ボタンの名前は、文書の表記(英語)のままです。

GitHub のプルリクエストの画面で解く

GitHub の画面で解けるのは、同じ行を別々に変えた、単純なコンフリクトだけです。それ以外のコンフリクトは、手元のコマンドで解きます。

注意: 画面で解くと、base branch(取り込み先のブランチ)全体が、head branch(プルリクエストのブランチ)にマージされます。head branch が既定のブランチや保護されたブランチなら、新しい head branch を作るよう求められることがあります。

手順は、GitHub の文書では次のとおりです。

  1. リポジトリ名の下の Pull requests を押す
  2. 一覧から、コンフリクトのあるプルリクエストを開く
  3. 下のほうの Resolve conflicts を押す
  4. 自分の側だけ・相手の側だけ・両方を合わせた新しい中身のどれにするか決める
  5. マーカー(<<<<<<<・=======・>>>>>>>)を消して、残したい中身にする。1つのファイルに何か所もあれば、次のマーカーまで下へ動いて繰り返す
  6. そのファイルを全部解いたら、Mark as resolved を押す
  7. ほかのファイルにもコンフリクトがあれば、左の「conflicting files」の下で次のファイルを選び、4〜7を全部のコンフリクトが解けるまで繰り返す
  8. 全部解いたら Commit merge を押す(base branch 全体が head branch にマージされます)
  9. 聞かれたら、コミットする先のブランチを確かめる。head branch を更新するか、新しいブランチを作れるとき(文書の「if available」)は新しいブランチを作る。head branch が保護されていれば、新しいブランチを作らなければならない。Create branch and update my pull request か I understand, continue updating BRANCH を押す(BRANCH のところには、実際のブランチ名が入ると読めます)
  10. マージするには Merge pull request を押す

Resolve conflicts が押せない(deactivated)ときは、別の Git の道具か、コマンドで解きます。ファイルを消したコンフリクト(片方が消し、片方が書き換えた)も、コマンドの文書が別の節にしています。残すなら git add <ファイル>、消すなら git rm <ファイル> をして、コミットします。

手元のコマンドで解いたあとは、手元でマージを終えるか、GitHub に push して、プルリクエストでマージします。プルリクエストを手元に取ってくる方法は、プルリクエストとは?の記事で紹介しています。

文書によると、Copilot cloud agent が有効なリポジトリでは、マージの欄の Fix with Copilot で、Copilot にコンフリクトを解かせることもできます。使える条件(プランや料金)は、調べていません。

VS Code で解く

VS Code の文書では、ぶつかった所の上に、次のボタンのような文字(CodeLens)が出ます。

  • Accept Current Change: 今の側だけ残す
  • Accept Incoming Change: 入ってくる側だけ残す
  • Accept Both Changes: 両方を順に残す
  • Compare Changes: 見比べる

「Current(今の側)」と「Incoming(入ってくる側)」の意味は、場面で変わります。VS Code の文書は「Current は、いつも元の feature ブランチとは限らない」と注意しています。

場面CurrentIncoming
merge(pull の merge を含む)チェックアウトしている取り込み先取り込むブランチ
rebase(Pull (Rebase) を含む)新しい土台と、載せ直し済みのコミットいま載せ直している自分のコミット
cherry-pickチェックアウトしているブランチ当てるコミット
stash を戻す戻す先の作業の状態stash の変更

3方向のマージエディターは、ソース管理の「Merge Changes」の下のファイルを右クリックして Open in Merge Editor を選ぶと開きます。解いたら Complete Merge を押します。Complete Merge はそのファイルを add して閉じるだけで、マージ全体は終わりません。 merge は、ソース管理の画面でメッセージを書いて Commit します。rebase は統合ターミナルで git rebase --continue、cherry-pick は git cherry-pick --continue です。どの操作の途中か分からなければ git status を流します。やめるときは、コマンドパレット(Mac は ⇧⌘P、Windows・Linux は Ctrl+Shift+P)で Git: Abort Merge・Git: Abort Rebase・Git: Abort Cherry Pick を選びます。

よくある質問

マーカーの HEAD は、上と下のどちらが自分の側?

merge では、<<<<<<< HEAD の下(======= まで)が、merge を実行したときにいたブランチ、つまり自分の側です。下が取り込んだ相手の側です。ただし、rebase と git pull --rebase では逆で、HEAD の側は載せる先(main やリモート)、下の側が載せ直している自分のコミットです。stash pop では、Updated upstream がいまのブランチの側、Stashed changes が stash の側です。

git merge --abort で「MERGE_HEAD missing」と出るのは?

マージの途中ではない(MERGE_HEAD が無い)ときに出ます(「There is no merge to abort」)。手元の git 2.39.3 では、次の場面でこの表示になりました。もう --abort をしたあと、「would be overwritten by merge」で merge が始まる前に止まったあと、そして stash pop・rebase・cherry-pick のコンフリクトの途中です。rebase なら git rebase --abort、cherry-pick なら git cherry-pick --abort を使います。stash pop には --abort が無いので、前の節の戻し方になります。

GitHub で「Resolve conflicts」が押せないのは?

GitHub の画面で解けるのは、同じ行を別々に変えた単純なコンフリクトだけで、それ以外はコマンドで解く、というのが文書の説明です。押せないときは、別の Git の道具か、コマンドで解きます。片方がファイルを消し、もう片方が書き換えたコンフリクトも、コマンドで解きます(git add か git rm)。どの場面で押せなくなるかの一覧は、見つかりませんでした。

コンフリクトの解き方を間違えたら、やり直せる?

コミットする前なら、git merge --abort でマージの前に戻して、最初からやり直せます(解きかけた中身は消えます)。ファイルのコンフリクトの状態だけを作り直したいなら、git restore --merge <ファイル> です。手元の git 2.39.3 では、git add したあと(コミットの前)でも、作り直せました。

コミットして push したあとの取り消し方は、この記事では扱いません。Git で取り消すには?の記事のとおり、マージを revert すると、あとで同じブランチをマージし直しても、revert したマージに含まれていた変更は入ってこない、という注意があります。

まとめ

  • コンフリクトは、同じ所を別々に変えたとき(と、片方が消し、片方が書き換えたとき)に起きる。merge のほか、rebase・cherry-pick・revert・stash pop・pull でも起きる
  • ぶつかったファイルは git status(短くは UU など)で分かる。マーカーの上半分は、いつも自分の側ではない。rebase と git pull --rebase では、HEAD と --ours は載せる先の側
  • 解くには、ファイルを直してマーカーを消し、git add して、git commit か --continue。消し忘れても add と commit は止まらない(手元の git 2.39.3 では)ので、git diff --check で確かめる
  • やめるには --abort(merge・rebase・cherry-pick)。ただし、解きかけた中身は消える。merge の前の未コミットの変更は、戻らないことがある。stash pop には --abort が無い
  • --ours・--theirs で中身を選んでも、git add が要る。-X ours(ぶつかった所だけ)と -s ours(相手の変更を全部捨てる)は別もの
  • GitHub の画面で解けるのは、同じ行の単純なコンフリクトだけ。画面で解くと、base branch 全体が head branch に入る

参考資料

※この記事は、公式の資料をもとに AI(Claude)で下書きし、2026年10月14日時点の公式の資料と照らして確かめてから公開しています。誤りに気づいたらお問い合わせからお知らせください。

PR
PR
タイトルとURLをコピーしました