よくある話が、コミットを取り消したいだけなのに、コマンドが複数あって迷う場面。
ところが、git resetには--soft・--mixed・--hardという3つのオプションがあり、git revertという別のコマンドもある。
そこで、この記事では「取り消したい範囲」と「共有済みかどうか」という2つの判断軸で、それぞれの使い分けを整理した。

resetとrevert、何が違うのか
どちらも「なかったことにする」コマンドだが、履歴を消すか、履歴を残すかが決定的に違う。
| コマンド | 何をするか | 使うタイミングの目安 |
|---|---|---|
| reset –soft | コミットだけ取り消す(変更はステージに残る) | 直前のコミットメッセージや粒度をやり直したいとき |
| reset –mixed | コミットとステージを取り消す(変更はワーキングツリーに残る) | ステージし直してからコミットしたいとき(デフォルト挙動) |
| reset –hard | コミット・ステージ・変更内容すべてを消す | その変更ごと丸ごと不要になったとき |
| revert | 取り消し内容を新しいコミットとして追加する | 共有済みのブランチで、履歴を残したまま取り消したいとき |
resetは履歴そのものを書き換え、revertは打ち消しの記録を積み増す。この一点さえ押さえれば、どちらを使うべきかはほぼ自動的に決まる。
git resetの3つのオプション
–soft:コミットだけ取り消す
直前のコミットを取り消しつつ、変更内容はステージされた状態のまま残す。
git reset --soft HEAD~1コミットメッセージを書き直したい、あるいは複数のコミットを1つにまとめ直したいときに使う。
–mixed:コミットとステージを取り消す(デフォルト)
オプションを省略した場合の挙動。コミットとステージを取り消し、変更内容はワーキングツリーに残す。
git reset HEAD~1
# git reset --mixed HEAD~1 と同じファイルの内容は消えないので、ステージするファイルを選び直してコミットし直したいときに使う。
–hard:全部消す
コミット・ステージ・ワーキングツリーの変更内容まで、すべて指定した状態に巻き戻す。変更内容そのものが消える、唯一のオプション。
git reset --hard HEAD~1実行前に、消えて困る変更が残っていないか必ず確認したい。地味に見落としがちだが、--hardはワーキングツリーの未コミット分も巻き込んで消える。
共有ブランチではrevertを使う
resetはコミット履歴そのものを書き換えるコマンド。すでにリモートへpush済みで、他の人が同じブランチを見ている場合にresetすると、履歴の食い違いが起きる。
そこで使うのがrevert。取り消したいコミットを打ち消す、新しいコミットを追加する形で処理する。
git revert <取り消したいコミットのハッシュ>履歴を書き換えないので、他の人の作業に影響を与えない。「まだ自分しか見ていないローカルの作業ならreset、すでに共有したらrevert」と覚えておけば判断に迷わない。
–hardで消しすぎたときの復旧:reflog
もしreset --hardで必要なコミットまで消してしまっても、多くの場合はreflogから復旧できる。
git reflog
# 一覧からコミットハッシュを確認して
git reset --hard <復旧したいコミットのハッシュ>reflogはHEADの移動履歴を記録しているので、resetやrebaseのやり直しにも使える保険。ただし記録には期限があるので、過信は禁物。
よくある質問
本文で触れきれなかった細かい疑問をQ&Aでまとめておきます。
git resetとgit checkoutの違いは何ですか?
resetはブランチの指すコミット自体を移動させます。checkout(新しいGitではgit restore)は、特定のファイルの中身を指定したコミット時点の状態に戻すだけで、コミット履歴自体は動きません。
複数のコミットをまとめてresetするには?
HEAD~1の数字を変えることで、さかのぼるコミット数を指定できます。例えば直近3件をまとめて取り消したい場合はgit reset --soft HEAD~3のように書きます。
revertで複数コミットをまとめて取り消せますか?
git revert <古い方のハッシュ>..<新しい方のハッシュ>のように範囲指定すれば、複数コミットをまとめて打ち消すコミットを作成できます。ただしコンフリクトが起きやすくなるため、範囲が広い場合は1件ずつ確認しながら実行するほうが安全です。
まとめ
取り消す範囲で選ぶならsoft・mixed・hardのどれか、共有済みかどうかで選ぶならreset・revertのどちらか。この2軸を意識するだけで、取り消し系コマンド選びに迷わなくなる。

コメント