Git:ブランチの削除、マージ、そして誤ったpushの取り消し
August 2, 2026 · – 訪問者
この3つはしょっちゅう出てくるのに、なぜかコマンドが毎回きちんと頭に残らない。というわけで、ここにきちんと書き留めておく。
ブランチの削除
git branch -d feature-x
これは安全なバージョンだ——Gitはまず確認し、feature-xに現在のブランチへ取り込まれていないコミットがあれば削除を拒否する。確実だと分かっているなら、強制的に上書きできる (1)。
git branch -D feature-x
ただし、これはローカルでの削除にすぎない。ブランチがリモート(たとえばGitHub)にも存在する場合は、そちらも別途削除する必要がある。
git push origin --delete feature-x
知っておく価値があるのは、ブランチを削除しても、実はそのコミット自体は削除されないということだ。コミットは参照されなくなるだけで、Gitのガベージコレクタがいずれ掃除するまでリポジトリの中に残り続ける。これには結構な時間がかかることもある。だからgit branch -Dは見た目より寛大だ——間違ったブランチを削除してしまっても、たいていはまだ戻る道がある(詳しくは下のreflogの節で扱う)。それを当てにした計画は立てないが、そういう逃げ道があると知っておくのは悪くない。
ブランチのマージ
よくある形はこうだ。マージ先にしたいブランチをチェックアウトし、そこにもう一方を取り込む。
git checkout main
git merge feature-x
次に何が起こるかは、ブランチを切った後にmainが進んでいるかどうかで決まる。進んでいなければ、Gitはmainのポインタを単純にfeature-xまで前進させるだけだ——これがfast-forwardで、マージコミットは発生しない。その間にmainが進んでいた場合は、Gitが両方の履歴をつなぐ実際のマージコミットを作成する (2)。
fast-forwardが可能な場合でも、あえてそのマージコミットが欲しいときがある——そうすることで、変更が静かに紛れ込むのではなく、feature branchが存在してマージされたという目に見える印を履歴に残せる。そのためには次のようにする。
git merge --no-ff feature-x
両側で同じ行が変更されていた場合、Gitは処理を止め、コンフリクトの解決をこちらに委ねる。
git status
これでコンフリクトしているファイルが一覧表示される。それぞれを開くと、競合する変更を囲む<<<<<<<、=======、>>>>>>>というマーカーが見つかる——実際に残すべき内容を選び、マーカーを削除したら、次を実行する。
git add resolved-file.txt
git commit
そして、それが手間に見合わないほどの混乱になってしまったら、その場から丸ごと立ち去ってしまってもいい。
git merge --abort
これで、マージを始める前の状態にすべてが正確に戻る。
誤ったpushの取り消し
これは人々が一番パニックになりがちな状況だが、正直なところ、そのパニックはたいてい根拠がない——ただし、ここではどの対処法を選ぶかが実際に重要になってくる。
誰かがすでにそのブランチをpullしている可能性が少しでもあるなら、履歴には手を出さないこと。代わりに、古いコミットを打ち消す新しいコミットを追加する。
git revert <bad-commit-sha>
git push
これは地味だが、常に安全な選択肢だ。何も書き換えることなく、間違いを打ち消すコミットを上に積むだけなので、誰もが特別なことをする必要もなく、全員の履歴が同期されたままになる (3)。
そのブランチが本当に自分だけのもので、まだ誰もpullしていないなら、巻き戻して書き換えることができる (4)。
git reset --hard <last-good-commit-sha>
git push --force-with-lease
せめて習慣として、素の--forceではなく--force-with-leaseを使うようにしよう。この違いは見た目以上に重要だ。--force-with-leaseは、最後にfetchしてから誰もそのブランチにpushしていないことを確認し、もし誰かがpushしていれば拒否する。素の--forceは何も確認しない——警告一つなく、平然と他人の作業を上書きしてしまう (5)。
そして、最後に無事だったコミットが何だったか思い出そうと端末を見つめているなら——git logはここでは役に立たない。今いる場所から到達できるコミットしか表示せず、すでにresetで捨てたものは含まれないからだ。本当に必要なのはこれだ。
git reflog
これは、ブランチが最近指していたすべての位置を示してくれる。通常の履歴からこぼれ落ちてしまったものも含めてだ。物事がおかしくなる前の状態までさかのぼったら、次を実行する (6)。
git reset --hard HEAD@{2}
(実際の状況に合った位置やSHAに置き換えること)。reflogは自分のマシンにローカルなもので、通常はエントリを90日ほど保持する。だから「誤ったpushのための緊急取り消し手段」というよりは、「何かを壊してしまった気がする」というときのための一般的な安全網に近い——この場面に限らず、存在を覚えておく価値がある。
結びに
この3つはすべて、同じ根本的な事実に支えられている。Gitはほとんど何も即座には捨てない、ということだ。削除されたブランチ、resetされたコミット、ブランチ上の古い位置——これらはすべて、見た目以上に長く残り続ける。だからこそ-Dやreset --hard、force-pushは日常的に使っても十分安全なのだ。ただし、それが間違いだったと判明したときにどこを探せばいいかを知っている限りにおいて、という条件付きで。
関連記事
- Makeを理解する — 再ビルドを実際に引き起こすもの
参考文献
- git-branch — ブランチの作成、一覧表示、削除。
- git-merge — マージ戦略とコンフリクトの解決。
- git-revert — 新しいコミットを作成することで既存のコミットを取り消す方法。
- git-reset — ブランチのポインタを動かす方法、および
--soft、--mixed、--hardの違い。 - git-push: --force-with-lease —
--forceよりも安全な理由。 - git-reflog — 通常の履歴にはもう表示されないコミットを復旧する方法。
コメント