【Git】git mergeを取り消す方法を初心者向けに解説

Web開発

はじめに

Gitを使って開発をしていると、意図しない状態でブランチをマージしてしまうことがあります。 例えば、まだレビューされていない機能を誤ってメインブランチに統合してしまったり、衝突解消時に余計な差分が生まれたりするケースです。

こうした状況では、マージそのものを取り消したいという要望が出てくるかもしれません。 今回は、git mergeを取り消すための基本的な方法を解説していきます。

初心者の皆さんが混乱しやすいポイントをわかりやすくまとめることで、実際の開発現場でも落ち着いて対応できるような知識を身につけていただくことがこの記事の狙いです。

この記事を読むとわかること

  • Gitにおけるmerge(マージ)の役割
  • マージの取り消しが必要になる代表的なシーン
  • revert コマンドを使ったマージの取り消し方法
  • reset コマンドを使ったマージの取り消し方法
  • それぞれの方法を使う際の注意点と実務での活用アイデア

Git mergeとは?

Gitにおけるmergeは、別々のブランチで進めていた開発内容を1つに統合するときに使うコマンドです。 複数の開発者が同じリポジトリで作業するとき、各自が作成した機能や修正をマージによってメインブランチなどへ集約します。

多くの場合、作業者は次のような流れでマージを実行します。

  • 新機能や修正を別のブランチ(featureブランチなど)で開発する
  • 開発が完了し、不具合がないことを確認する
  • コードレビューなどを経て、メインブランチ(mainやmaster)にmergeする

最終的にマージされたブランチの内容は、全体のソースコードと統合された状態になります。 ところが、マージ先やマージ元を間違えたり、コンフリクトの解消を誤ったりして、想定外の変更がメインブランチに取り込まれてしまうことがあるわけです。

こうした事態をリカバリする方法として、「revert(リバート)」と「reset(リセット)」という代表的な2つのアプローチがあります。

マージを取り消したい理由

誤ったマージをしてしまう主な理由をいくつか挙げてみましょう。 初心者の皆さんが実務や学習で遭遇しやすい例も含まれていますので、同じ状況に出会ったときに思い出してみてください。

1. ブランチを間違えた

間違ったブランチに対してマージしてしまったケースです。 たとえば、テスト用ブランチをメインブランチにマージしようとしたのに、別の開発ブランチをメインブランチに統合してしまう。

2. コンフリクトの解消を誤った

コンフリクトが発生しているにもかかわらず、衝突部分のコードを誤って取り込んでしまうことがあります。 その結果、意図しない修正が加わったままコミットしてしまう場合です。

3. レビュー前のコードを誤って統合

まだレビューされていない機能や不安定なコードをうっかりマージし、本番環境に影響が及ぶリスクを生むケースも少なくありません。

実務での開発では、これらのミスが起きた場合にいち早くリカバリし、できるだけ余計な影響を最小限に食い止める必要があります。そのために「マージを取り消す」という操作が求められるわけです。

取り消しのアプローチ: revert

マージを取り消す際に最も安全な方法として一般的に推奨されるのが、revert コマンドを使うやり方です。

revertは、特定のコミットを打ち消すための操作を新たに別のコミットとして追加する方法と言えます。 マージコミットを取り消す場合も、revertを使えば「何を打ち消すか」を明確にしながら、履歴を壊さない形で元の状態に戻すことができます。

revertを使うメリット

履歴を壊さない

過去のコミットはそのまま残り、新たに「取り消し用コミット」が積み上がります。 そのため、チーム開発で履歴を共有するときでも混乱が少なくて済みます。

トラブルシュートがしやすい

どのコミットを打ち消すかが履歴上で明確なので、後から見返したときに何が起きたかがわかりやすいです。

ただし、revertでは複数のコミットを一度にまとめて取り消す場合などにやや複雑な指定が必要となることもあります。 マージコミットをrevertするときには、以下のような手順を踏むことが多いです。

revertでの実行手順

マージコミットをrevertしたいときは、まず打ち消したいマージコミットのハッシュ値を確認します。 コミットハッシュは git log --onelinegit reflog などで把握できます。

例えば、以下のようにコミットログが表示されるとします。

$ git log --oneline
abcd123 (HEAD -> main) Merge branch 'feature-a'
efgh456 Add new file
ijkl789 Update README

ここで abcd123 がマージコミットにあたると仮定すると、次のようにrevertを実行します。

git revert -m 1 abcd123

-m 1 は、マージコミットをどの親として扱うかを指定するオプションです。

通常、メインブランチ(masterやmain)が親1の場合は、-m 1 を指定するケースが多いです。 これはマージコミットの元となるブランチが2つ以上あるため、そのうちどのブランチを基準として取り消すかを決める必要があるからです。

revertが完了すると、新たに「マージコミットを取り消した」というコミットが作られます。 Gitの履歴上では、過去にマージが行われた事実は残りますが、現在のソースコード状態はマージ前に近い形に戻るというわけです。

マージコミット以外をrevertするときは、-m オプションを付けず、打ち消したいコミットハッシュを指定するだけでOKです。

取り消しのアプローチ: reset

次に、もうひとつの方法としてresetを使うやり方があります。 resetは特定のコミット時点に履歴を巻き戻すコマンドで、過去のある地点までコミット履歴を戻すことができます。

resetを使うときには、主に以下の3種類のオプションが存在します。

--soft

コミット履歴だけを指定の位置に戻し、ワーキングツリーはそのままにする

--mixed

コミット履歴とステージング(インデックス)を戻し、ワーキングツリーはそのまま

--hard

コミット履歴・ステージング・ワーキングツリーもすべて指定の位置に合わせて戻す

マージを取り消すという観点で考えると、すでに誤ったマージが反映されたコミットよりも1つ前のコミットに戻すために、--hard を指定して履歴ごと戻してしまうパターンが多いです。 しかし、この場合は履歴が書き換わることになるため、チーム開発の状況によっては混乱が生まれる可能性がある点に注意してください。

resetでの実行手順

--hard オプションを使って、特定のコミットまで履歴を巻き戻す例を見てみましょう。

1. マージが行われる前のコミットハッシュを確認する

git log --onelinegit reflog で、マージ前の最新コミットを特定します。

2. git reset --hard <コミットハッシュ> を実行する

例えば、マージ前のコミットが ijkl789 である場合、次のようにします。

git reset --hard ijkl789

コミットハッシュの代わりに HEAD^(1つ前のコミット)や HEAD~2(2つ前のコミット)などを使うこともあります。 例えば、直前のマージコミットだけを取り消したい場合は以下のようにします。

git reset --hard HEAD^

resetで巻き戻した場合、ブランチの履歴から誤ったマージコミットそのものが消えた形になります。 そのため、チームメンバーが既に更新されたブランチを取得していると、履歴が食い違ってしまう可能性があります。 リモートリポジトリにプッシュ済みの場合は、resetの利用に慎重になることをおすすめします。

resetは履歴を書き換えるため、チームが共有するブランチよりも個人の作業ブランチで使うほうが混乱が少ないです。

取り消し後の注意点

マージを取り消した後にも、いくつか気を付けておきたいことがあります。 状況に応じて取り扱い方が変わるので、以下のポイントは押さえておきましょう。

リモートブランチとの同期

revertの場合は、履歴を壊さずに打ち消しコミットを積む形なので、リモートにプッシュするときも比較的トラブルが少ないでしょう。 一方でresetの場合は、ローカルの履歴を巻き戻した状態をリモートに反映させようとすると、強制プッシュ(git push --force など)が必要になる場合があります。 この強制プッシュは、他のメンバーの履歴にも影響を及ぼす可能性があるため、チーム全体で合意したうえで慎重に行う必要があります。

コンフリクトの再発

revertでもresetでも、マージを取り消したあとに再度ブランチをマージしようとすると、以前コンフリクトがあった箇所や差分が再度現れる可能性があります。 取り消した原因が何だったのかを分析し、もしコード自体の問題があったなら、それを修正してからあらためてマージしましょう。

開発フローのルール

チームの開発ルールとして、誤ったマージはrevertで対応するのか、あるいはresetも許容するのかを予め決めておくと混乱を避けやすくなります。 実務の現場では、ヒューマンエラーを完全にゼロにすることは難しいです。 しかし、どう対処するかをあらかじめ共有しておけば、いざというときに落ち着いて対応できるでしょう。

まとめ

git mergeによって統合した内容を取り消す方法として、revertreset の2種類を紹介しました。 初心者の方には、まずは安全性の高いrevertで対処する習慣を身につけることをおすすめします。

resetはコミット履歴を巻き戻してしまうため、リモートリポジトリやチームメンバーへの影響を踏まえて慎重に判断することが大切です。 どちらの方法を選んだ場合でも、マージ前のコミットをきちんと把握しておくことや、コンフリクトが再発しないように注意する点がポイントになります。

Gitは複数のブランチを自由に切り替えながら開発できる便利なツールですが、その分誤操作も起こりやすいです。 誤ったマージが発生してしまったときは、今回ご紹介したrevertとresetの手順を参考に対処してみてください。 慣れてくると、ブランチ運用におけるリカバリ方法の幅が広がり、様々な開発チームのルールにも対応しやすくなります。

以上がgit mergeを取り消すための基本的な考え方と手順です。 しっかり身に付けておくことで、いざというときに落ち着いて対応できるようになるでしょう。

Gitをマスターしよう

この記事で学んだGitの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。