こんにちは、かつコーチです。
前回はコンフリクトの解決方法を解説しました。
コミットに慣れてくると、次に気になるのが「間違えたコミットを取り消したい」という場面です。
Gitにはgit resetとgit revertという、似ているようでまったく性質の違う2つのコマンドが用意されています。
今回はこの2つの違いと、それぞれの使いどころを整理していきましょう。
git resetとgit revertとは
過去に戻る(reset)vs 訂正の張り紙を貼る(revert)
git resetは、原稿そのものを過去のページに戻すようなコマンドです。
3ページ目まで書いた原稿を、2ページ目の状態まで巻き戻す。
3ページ目に何を書いたかという記録自体が、なかったことになります。
一方git revertは、過去のページはそのままに、「この変更は取り消します」という訂正の張り紙を新しいページに貼るコマンドです。
3ページ目の記述は残ったまま、4ページ目に「3ページ目の内容を打ち消します」という新しいページが追加される、というイメージです。
両者の決定的な違い:履歴を書き換えるかどうか
この違いを技術的に言い換えると、次のようになります。
git reset:コミット履歴を過去に巻き戻す(該当コミットが履歴から消える)git revert:打ち消す内容を新しいコミットとして追加する(履歴は消えず、増える)
この「履歴を書き換えるか、履歴を追加するか」という違いが、使い分けを決める最大のポイントになります。
git resetの使い方
–soft・–mixed・–hardの違い
git resetには3つのモードがあり、どこまで巻き戻すかが異なります。
| オプション | ステージ | 作業ディレクトリ | 用途 |
|---|---|---|---|
--soft | 変更を残す | 変更を残す | コミットだけやり直したいとき |
--mixed(デフォルト) | 変更を戻す | 変更を残す | ステージを解除して選び直したいとき |
--hard | 変更を戻す | 変更も消す | 変更ごと完全に無かったことにしたいとき |
--hardだけは、作業ディレクトリの変更内容そのものが失われる危険なオプションです。
具体例
直前のコミットを取り消して、コミット前の状態からやり直したい場合は次のようにします。
# 直前のコミットを取り消し、変更内容はステージに残す
git reset --soft HEAD^
# コミットメッセージを直したいだけならこちらでも十分
git commit --amend
「変更内容ごと完全になかったことにしたい」場合は--hardを使います。
# 直前のコミットと変更内容を完全に消す(要注意)
git reset --hard HEAD^
git revertの使い方
基本の使い方
特定のコミットの内容を打ち消したい場合は、git revertにコミットハッシュを指定します。
# 直前のコミットを打ち消す新しいコミットを作る
git revert HEAD
これを実行すると、エディタが開いてコミットメッセージの確認を求められます。
デフォルトではRevert "元のコミットメッセージ"という内容が入っているので、そのまま保存すれば完了です。
複数コミットをrevertする
複数のコミットをまとめて打ち消したい場合は、範囲を指定します。
# 直近3件のコミットをまとめて打ち消す
git revert HEAD~3..HEAD
コミットごとにエディタでの確認が挟まるのが煩わしい場合は、--no-editオプションでデフォルトメッセージのまま進められます。
git revert --no-edit HEAD~3..HEAD
使い分けの判断軸
個人ブランチか、共有ブランチか
resetとrevertのどちらを使うべきかは、そのコミットがすでにpushされて他人と共有されているかで判断します。
| 状況 | おすすめ | 理由 |
|---|---|---|
| 自分だけのローカルブランチ、まだpushしていない | reset | 履歴を消しても誰にも影響しない |
| すでにpush済み、他のメンバーがpullしている可能性がある | revert | 履歴を消すと、他メンバーの履歴と食い違いが起きる |
push済みかどうかで選ぶ
これを一言でまとめると、「まだ自分だけのメモ書き段階ならreset、すでに人に見せた原稿ならrevert」という判断軸になります。
一度共有した原稿のページを勝手に破り取ってしまうと、同じ原稿を見ている他の人との間で内容がズレてしまいます。
だからこそ、共有済みの履歴に対しては「破り取る(reset)」のではなく「訂正の張り紙を足す(revert)」方が安全なのです。
よくあるつまずきポイント
push済みのコミットにreset –hardして事故る
私が実際にヒヤリとした経験が、まさにこのケースです。
❌ Before:共有ブランチでreset –hardしてしまう
# すでにpush済みで、チームメンバーがpullしているコミットを…
git reset --hard HEAD^
# 履歴を無理やり合わせるために強制push
git push --force
--forceでpushすると、リモート側の履歴も自分のローカルに合わせて書き換えられてしまいます。
その結果、すでにそのコミットをpullしていたメンバーの手元では、履歴の整合性が取れなくなり、原因不明のコンフリクトやエラーに悩まされることになります。
私自身、検証用に立てたブランチで一度この事故をやってしまい、チームメンバーに「履歴がおかしくなった」と連絡が来て青ざめた経験があります。
✅ After:共有ブランチではrevertを使う
# 履歴を残したまま、打ち消しコミットを追加する
git revert HEAD
git push
revertであれば、既存の履歴を壊さずに済むため、通常のpushで安全に共有できます。
「一度でも人に共有した履歴は書き換えない」というのは、Gitを使ううえでの鉄則の1つとして覚えておいてください。
まとめ
この記事のポイント
git resetは履歴そのものを過去に巻き戻す「過去に戻る」操作git revertは打ち消しの内容を新しいコミットとして積み増す「訂正の張り紙を貼る」操作resetには--soft・--mixed・--hardの3モードがあり、--hardは変更内容ごと消えるので要注意- 自分だけのローカルブランチなら
reset、push済みの共有ブランチならrevertを選ぶ - push済みコミットへの
reset --hard+強制pushは、チームの履歴を壊す事故につながる
次に読むべき記事
履歴の取り消し方が分かったら、次は作業を一時的に退避させるgit stashの使い方を見ていきましょう。
→ 次の記事:git stashで作業を一時退避する
タグ: Git, 中級者向け, 履歴操作