【Git】マージの取り消し方法|merge –abort・reset・revert -m の状態別完全ガイド

「マージ中にコンフリクト解決に失敗したのでやり直したい」「マージしたものの方向が間違っていた」「pushしたmergeを打ち消したい」——Gitでのマージ取り消しはマージがどの段階まで進んでいるかで手順が変わります。コンフリクト解決中の中断と、commit済みの巻き戻し、push済みの打ち消しでは使うコマンドが全く違います。

この記事では、Gitのマージを取り消す方法をマージの進行状態(3段階)で整理し、git merge --abortgit resetgit revert -mの正しい使い分けを解説します。fast-forward mergeやsquash merge、octopus mergeといった特殊ケース、そして「revert後に再度マージしても取り込まれない」問題への対処まで、実務で迷わない形でまとめます。

この記事で学べること

  • マージの3段階(進行中/commit済み未push/push済み)と対応コマンド
  • git merge --abortで進行中マージを安全に中断する方法
  • 未push状態をgit resetで巻き戻す手順
  • push済みmergeをgit revert -mで履歴を残して打ち消す手順
  • fast-forward merge・squash merge・octopus mergeの取り消し
  • revert後の再マージ問題と回避策(cherry-pick/revert of revert)
  • 間違ったブランチにマージした場合のリカバリ
スポンサーリンク

まず判定:マージは今どの段階か?

取り消し方を選ぶ前に、マージがどこまで進んでいるかを確認します。git statusのヒントが最初の目印です。

状態 見分け方 推奨コマンド
A. マージ進行中(コンフリクト中など) git statusに「You have unmerged paths」 git merge --abort
B. マージcommit完了、未push git logにマージコミット、originに無し git reset --hard ORIG_HEAD
C. マージcommit完了、push済み リモートにマージコミットが存在 git revert -m 1 <M>

ポイント:判定のコツはgit statusgit log --oneline -5。「unmerged paths」表示がなければマージは一旦完了しており、あとはリモートに出ているかで未push/push済みを分けます。git log origin/main..HEADが空でないなら未push、空ならpush済みと判断できます。

状態A:進行中のマージを中断する(merge –abort)

git mergeを実行してコンフリクトが発生し、まだgit commitしていない状態です。git statusで「You have unmerged paths」や「use "git merge --abort"」と案内されているはずです。

マージを丸ごと中断
# 状態確認
git status
# → "You have unmerged paths."
# → (use "git merge --abort" to abort the merge)

# マージ開始前の状態に戻す
git merge --abort

# 念のため確認
git status
git log --oneline -3

merge –abort が行うこと

  • マージ開始前のHEAD位置に戻す(ORIG_HEADベース)
  • 作業ツリーもマージ前の状態に復元
  • ステージされた解決途中も破棄
  • マージ前にコミット済みだった自分の作業は消えない

注意:merge --abort「マージ中の途中解決」は破棄します。せっかく解決したconflictの手作業も失われます。解決した内容を残したければ、まずgit stashで退避を試みるか、解決済みファイルを別途コピーしてから--abortしてください。

状態B:マージcommit済み・未push → reset で巻き戻す

マージが完了してコミットが作られたが、まだpushしていない状態です。履歴書き換えが自由にできるので、git resetでマージ前まで巻き戻すのが最短です。便利な参照ORIG_HEADが「マージ直前のHEAD位置」を指しているので、これを使います。

reset –hard で巻き戻す
# マージ直前のHEADを確認
git log --oneline -5

# ORIG_HEAD はマージなど大きな操作の直前のHEADを指す
git log --oneline ORIG_HEAD -1

# 巻き戻し(作業ツリーごと戻す)
git reset --hard ORIG_HEAD

# 状態確認
git log --oneline -5

SHA直接指定でも戻せる

SHAを直接指定して reset
# マージ直前のコミットSHAを確認
git log --oneline --graph -10
# → マージコミットのひとつ前のSHAを探す

# そのSHAに戻す
git reset --hard a1b2c3d

# 変更は残したまま戻すなら --mixed
git reset --mixed a1b2c3d

ポイント:ORIG_HEADは「マージやリベース等の直前HEAD」を自動で覚えてくれる便利な参照です。git mergegit pullgit resetを実行するたびに更新されるため、マージ直後に取り消したいならORIG_HEADを使うのが最短。他の操作を挟むとORIG_HEADが上書きされるので注意(その場合はreflog参照に切り替え)。

戻しすぎたときは reflog で救済

reflogからマージ位置を特定
git reflog
# HEAD@{0}: reset: moving to ORIG_HEAD
# HEAD@{1}: merge feature: Merge made by...
# ↑ この位置に戻したければ
git reset --hard HEAD@{1}

resetの詳細は特定のコミットまで戻す方法、reflog救済はコミットの取り消し方も参照してください。

状態C:push済みマージ → revert -m で打ち消す

mainブランチにpush済みのマージコミットを取り消す場合、履歴を書き換えないためにgit revertで打ち消しコミットを追加します。マージコミットには2つの親があるため-mで基準にする親番号を指定します。

マージコミットの revert
# マージコミットのSHAを確認
git log --oneline --merges -5
# 出力例: a1b2c3d Merge branch 'feature/xxx' into main

# 親番号を確認
git show --no-patch --pretty=raw a1b2c3d
# parent 行が2つ出る。通常、1つ目がマージ先(main)、2つ目が取り込んだブランチ

# -m 1 でマージ先(main)を基準に打ち消し
git revert -m 1 a1b2c3d

# コンフリクト時
git add .
git revert --continue

# リモートに反映
git push origin main

-m 1 と -m 2 の違い

  • -m 1親1(マージ先=main等)を基準に打ち消し。「機能ブランチを取り込む前の状態に戻す」のが通常
  • -m 2親2(取り込んだブランチ=feature等)を基準に打ち消し。「機能ブランチ側に戻す」(稀)
  • 通常のfeature→main マージを取り消すなら-m 1が正解
  • 親の関係はgit show --pretty=raw <M>parent行で確認可能

マージコミット取り消しの詳細はmergeコミットを取り消して履歴を元に戻す方法で深掘り解説しています。

revert後の再マージ問題:取り消した機能を再導入するには

「あとから同じ機能を再びマージしたい」とき、単にgit mergeを実行しても打ち消しコミットが勝って取り込まれないという有名な罠があります。対処法を2つ紹介します。

なぜ再マージが効かないか

Gitはマージ対象の変更を「既に親のどこかに取り込んでいるか」でスキップを判断します。mainに打ち消しコミットが入ると「feature側の変更は一度取り込んで打ち消した」状態になり、再度git merge featureしても「既に取り込み済み」とみなされて何も起きません。

対処①:打ち消しコミット自体をさらにrevert

revert of revert
# 最初のマージを打ち消したコミット(= revert commit)のSHAを確認
git log --oneline

# その打ち消しコミットをもう一度打ち消す
git revert <revert_commit_SHA>

# こうすると「機能を再導入するコミット」が積まれる
git push

対処②:feature側で整理してからマージし直し

機能ブランチを再構築してマージ
# 取り込みたい変更を feature 側に新コミットとして積み直す
git switch feature/xxx
# 必要な修正を加えてコミット
git commit -am "feat: re-apply the undone feature with improvements"

# 改めてmainへマージ
git switch main
git merge feature/xxx

ポイント:「いったん取り消したが、問題を直してやっぱり入れたい」状況はよくあります。運用としては対処②のほうが履歴が読みやすいのでおすすめ。「なぜ取り消したか」と「何が改善されたか」が新コミットのメッセージで説明できます。

特殊ケース:fast-forward / squash / octopus merge の取り消し

fast-forward merge(マージコミット無し)の取り消し

マージ先ブランチの先端がマージ元の先祖だった場合、Gitはfast-forward(FF)でマージコミットを作らずポインタを進めます。この場合-mが使えないため、revertは個別コミット単位、またはresetで巻き戻します。

FF merge の打ち消し
# ① reset で戻す(未push個人ブランチ)
git reset --hard &lt;FFマージ前のSHA&gt;

# ② 個別コミットをrevertで打ち消す(push済み)
git revert &lt;SHA1&gt; &lt;SHA2&gt; ...

# ③ まとめてrange指定
git revert --no-commit &lt;開始SHA&gt;^..&lt;終了SHA&gt;
git commit -m "revert: FFで取り込んだ全変更を打ち消し"

FFを避ける設定

常にマージコミットを残しておくと、後の取り消しが-m 1で一発でできます。git config --global merge.ff falseで「マージコミットを必ず作る」設定にすると、コマンドオプションを毎回付ける必要がなくなります。--ff-onlyを明示してFFだけ許すポリシーもあります。

squash merge の取り消し

GitHubの「Squash and merge」などで取り込んだ場合、マージ元コミット群が1つに押し固められた単一コミットとしてmain側に積まれます。マージコミットではないので-mは不要、通常のgit revertで打ち消せます。

squash merge の打ち消し
# squashで作られた1コミットを通常のrevertで打ち消す
git revert &lt;squash_commit_SHA&gt;

# push
git push origin main

octopus merge(3つ以上の親)の取り消し

まれにgit merge A B Cのように3つ以上のブランチを同時マージするケースがあります。親番号1〜Nを持つため-mで基準を選びますが、通常は-m 1(最初に取り込まれたマージ先)を基準にします。

octopus merge の打ち消し
# 親一覧を確認
git show --no-patch --pretty=raw &lt;M&gt;
# parent行が3行以上ある

# 親1を基準に打ち消し
git revert -m 1 &lt;M&gt;

間違ったブランチにマージしてしまった場合

「featureブランチをmainにマージすべきがstaging にマージしてしまった」というケースは、取り消し+正しい場所にマージしなおすのが基本です。

間違ったマージを修正する
# STEP 1: 間違ったブランチで状態確認
git switch wrong-target-branch
git log --oneline --merges -3

# STEP 2: マージを打ち消す
# pushしていないなら
git reset --hard ORIG_HEAD
# pushしているなら
git revert -m 1 &lt;マージSHA&gt;
git push

# STEP 3: 正しいブランチに移動してマージ
git switch correct-target-branch
git pull origin correct-target-branch
git merge feature/xxx
git push

誤マージを防ぐ運用

  • PRベースの運用:GitHubのbase branchを選ぶ画面で再確認
  • Branch protection:main/stagingをprotectedにして誤マージを拒否
  • CODEOWNERSでレビューアを必須化
  • コミット前にgit branch --show-currentでブランチ確認

GUI・IDEでのマージ取り消し

主要ツール

  • VS Code / Cursor:conflict発生時はSource Controlで「Abort Merge」ボタン、GitLensで過去マージをRevert
  • JetBrains(IntelliJ/WebStorm):Merge Conflicts ダイアログの「Abort」、Git Log右クリック→Revert Commit
  • SourceTree:Stop Merge ボタン、過去commit右クリック→Reverse Commit
  • GitHub Web:PRページの「Revert」ボタンでマージ打ち消しPRが自動生成(-m 1相当)
  • GitKraken:commit右クリック→Revert Commit

GitHubのRevertボタン

ポイント:GitHubの「Revert」ボタンは裏でgit revert -m 1相当を実行し、打ち消し用の新しいPRを作ってくれます。コンフリクトが無い場合はワンクリックで取り消しPRができるので、push済みマージの取り消しには最も安全な選択肢です。

実践シナリオ

シナリオ① pullでconflict、全部やり直したい

状態Aから脱出
git status        # "You have unmerged paths"
git merge --abort # やり直し

# 改めてpull戦略を選ぶ
git pull --rebase

シナリオ② さっきのmergeを未pushで戻す

状態Bから巻き戻し
git log --oneline -3
git reset --hard ORIG_HEAD

シナリオ③ push済みmainのマージを打ち消す

状態Cで revert
git log --oneline --merges -3
git revert -m 1 &lt;MERGE_SHA&gt;
git push origin main

シナリオ④ 取り消したfeatureを後で再度取り込みたい

revert of revert で再導入
# 打ち消しコミットをさらに打ち消す
git revert &lt;revert_commit_SHA&gt;
git push

履歴が複雑になったときの整理はpull後に大量のマージコミットが発生したときの原因と履歴整理方法も参考にしてください。

やってはいけない落とし穴

push済みマージを reset –hard + force push で取り消す

共有ブランチのマージをgit reset --hardgit push --forceで消すと、他メンバーのローカル環境を破壊します。共有ブランチは必ずrevert -mで打ち消しコミットを追加してください。個人ブランチでも--forceより--force-with-leaseを使うのが安全側です。

-m 1 と -m 2 を取り違える

-m 2を使うとマージ先ブランチの内容を打ち消してしまい、意図と逆の結果になります。通常のfeature→mainマージを取り消すなら-m 1(親1=main側を基準)が正解。不安ならgit show --pretty=raw <マージSHA>でparent行を確認してから実行しましょう。

merge –abort 前にconflict解決の手作業を保存しない

merge --abortは途中解決をすべて破棄します。せっかく解決したファイルの内容を別の場所にコピー/stashしておかないと、やり直し時に同じ作業を繰り返すはめになります。

revert後に再マージして「何も起きない」と混乱する

一度revertで打ち消したマージを、そのままgit mergeしても何も変わりません。「revert of revert」か「feature側で作業を積み直してマージ」で対応します。詳細は本記事の該当セクションを参照。

squash merge をマージコミットと勘違いする

GitHubの「Squash and merge」で取り込んだコミットは親が1つの通常コミットです。-m 1を付けてrevertしようとすると「not a merge」エラーになります。squashの場合は通常のgit revertで十分です。

よくある質問

Qreset と revert どちらでマージを取り消すべき?
A未pushの個人ブランチならreset --hard ORIG_HEAD、push済み・共有ブランチならrevert -m 1が原則です。resetは履歴を書き換え、revertは打ち消しコミットを追加するという大きな違いがあります。
QORIG_HEAD が期待と違う場所を指している
Aマージ後に他の操作(reset・rebase・pullなど)を行うとORIG_HEADが上書きされます。git reflogで履歴を遡り、マージ直前の位置を特定してgit reset --hard <SHA>で戻しましょう。
Qrevert -m 1 でコンフリクトが出た
A通常のマージコンフリクトと同じ手順で解消します。衝突ファイル修正→git addgit revert --continue。中止はgit revert --abort
QGitHubのRevertボタンと git revert -m 1 は同じ?
A実質的に同じです。GitHubのRevertボタンは裏でrevert -m 1相当を実行し、打ち消し用の新PRを自動生成します。コンフリクトが無ければこれが一番早くて安全です。
Qrevertで取り消したfeatureをもう一度マージしたい
A単に再度git mergeしても取り込まれません。打ち消しコミット自体をさらにrevertする(revert of revert)か、feature側で新コミットを追加してから再マージします。運用的には後者が履歴の意図が分かりやすくおすすめです。
Qfast-forward merge の場合 -m は使える?
A使えません。FFの場合はマージコミットが作られていないため、個別コミットをgit revertで打ち消すか、git resetで巻き戻します。常にマージコミットを残したい場合はmerge.ff = false設定が便利です。
Qreset したら未コミットの変更も消えた
A--hardは作業ツリーも破棄します。変更を残したいなら--mixed(既定)を。マージ取り消しの場合、--mixedだと部分的なファイルが残ってしまうので、巻き戻したうえで手動で必要な変更だけ再作成するのが現実的です。

関連記事

まとめ

  • マージ取り消しは3段階で使うコマンドが変わる:進行中→--abort/未push→reset/push済み→revert -m
  • マージ直前への巻き戻しはORIG_HEADが便利(他操作で上書きされる前に使う)
  • マージコミットのrevertは-m 1(マージ先基準)が通常パターン
  • revert後の再マージは効かない——revert of revert か feature側再構築で対応
  • fast-forward merge は個別commit revertかreset、squashは通常のrevert
  • 共有ブランチでreset --hard+force pushは禁止、必ずrevertで
  • 予防:PRベース運用・Branch protection・merge.ff=falseでマージコミットを残す

マージ取り消しは「状態判定」が9割です。git statusgit log --oneline --mergesで今どこに居るかを把握し、3段階の対応表にあてはめれば、慌てずに正しいコマンドを選べます。どの段階でもreflogがあるので90日以内なら救済できると知っておくと精神的にも楽です。共有ブランチの安全運用と、revert後の再マージ問題に気をつけながら、きれいで追いやすい履歴を保っていきましょう。