Gitで作業していると「さっきのコミット、やっぱりやり直したい」という場面に必ず遭遇します。コードを間違えて含めてしまった、コミットメッセージを打ち間違えた、公開しないファイルを入れてしまった、そもそも不要なコミットだった——原因はさまざまですが、焦ってgit reset --hardを叩くとかえって手元の作業を失うことがあります。
この記事では、Gitのコミットを取り消す方法を状況別に体系的にまとめ、「まだpushしていない/push済み」「変更は残したい/破棄したい」「メッセージだけ直したい」といったケースに対し、正しいコマンドと落とし穴、そして失敗したときのリカバリ方法までを解説します。Git公式ドキュメントと現場での実践パターンに沿って、安全に履歴を戻すための判断基準を手に入れましょう。
この記事で学べること
- コミット取り消しの前に確認すべきこと(push済みか・共有ブランチか)
git resetの--soft/--mixed/--hardの違いと使い分けgit commit --amendで直前のコミットを修正する方法- 公開済みブランチで安全に取り消す
git revertの使い方 - 複数コミットをまとめて取り消す・特定のコミットだけ取り消すテクニック
- 誤って
--hardしたときにgit reflogで救済する手順 - やってはいけない落とし穴(共有ブランチでの履歴改変・force push事故)
まず確認:2つの質問で取り消し方が決まる
取り消し方法を選ぶときに迷わないコツは、「pushしたか?」「変更は残したいか?」の2つの質問に答えることです。
- push済みか? → Yesなら
revert、Noならresetまたはamend - ファイルの変更は残したいか? → 残すなら
--soft/--mixed、破棄なら--hard
この2軸に「メッセージだけ直したい」「ファイルを追加し忘れた」などの頻出パターンを加えた早見表が以下です。最初にgit statusとgit log --oneline -5で現状を把握してから選びましょう。
ポイント:push済みや他メンバーが取得済みのブランチでは、原則としてrevertを使います。resetやcommit --amendは履歴を書き換えるため、共有後に行うと他の開発者の環境を破壊します。
取り消し前に必ず現状を確認する
取り消し作業で失敗する最大の原因は「何を取り消そうとしているか分かっていないまま操作する」ことです。まず以下のコマンドで、コミット履歴と作業ツリーの状態を把握しましょう。
# 直近5件のコミット履歴をSHAとメッセージで表示 git log --oneline -5 # 変更がステージに上がっているか、未コミットかを確認 git status # 指定コミットの差分を事前に確認 git show <SHA> # ブランチがリモートと比べて何コミット進んでいるか確認 git log --oneline origin/main..HEAD
特に重要なのは「このコミットはpush済みか?」という確認です。リモートに出ていない(origin/main..HEADに含まれる)コミットはresetで自由に消せますが、push済みの場合はrevertで打ち消すのが原則です。
直前のコミットを取り消して変更を残す(–soft)
「コミットは取り消したいが、変更したファイルは手元に残してもう一度やり直したい」というときはgit reset --soft HEAD~1を使います。コミットは消えますが、ファイルの変更はステージング(git add済み)の状態のまま残るため、ファイルの選び直しやメッセージの書き直しがすぐできます。
# 直前のコミットを1件取り消す(変更はindexに残る) git reset --soft HEAD~1 # 状態を確認:変更が「Changes to be committed」に残っていればOK git status # 必要に応じてファイルを追加・除外してから、新しいメッセージで再コミット git reset HEAD some_unwanted_file.txt # ステージから外すだけ git commit -m "修正後の正しいコミットメッセージ"
ポイント:--softはコミットの「巻き戻し」であり、変更内容は消しません。コミットを小分けに分割したい・メッセージを整えたい・ファイル範囲を見直したい、といった場合の第一選択肢です。
直前のコミットを取り消してステージングも解除する(–mixed)
git reset --mixed HEAD~1(オプション省略時のデフォルト)は、コミットを取り消したうえでステージングも解除します。ファイルの変更自体はワーキングツリーに残るため、git addをやり直しながらより慎重に分割コミットしたいときに向いています。
# --mixed はデフォルトなので省略可能 git reset HEAD~1 # 状態確認:「Changes not staged for commit」に変更が残っていればOK git status # 必要なファイルだけ add してから再コミット git add src/main.py git commit -m "main.py の修正のみをコミット"
–soft と –mixed の違い
- –soft:コミットだけ取り消す。
git add済みの状態は維持 - –mixed:コミットもステージングも取り消す。
git addからやり直す - –hard:コミット・ステージング・ワーキングツリーすべて破棄
直前のコミットを取り消して変更も完全に破棄する(–hard)
git reset --hard HEAD~1はコミットに加えてワーキングツリーの変更まで完全に消去します。「直近の変更が本当に不要・初期化してやり直したい」ときだけ使う強力なコマンドです。
# 直前のコミットと変更を完全に破棄 git reset --hard HEAD~1 # 2件前まで戻したい場合 git reset --hard HEAD~2 # 特定のSHAまで戻す git reset --hard a1b2c3d
注意:--hardは未コミットの変更も消えます。まだgit addしていない編集中のファイルもすべて失うため、作業中のファイルがある場合は先にgit stashで退避するか、本当に破棄してよいか確認してから実行してください。
もし--hardで誤って変更を消してしまった場合は、この記事のreflogによる救済セクションを参照してください。直近のHEAD位置はGitが履歴として保持しているため、復元できる可能性があります。
コミットメッセージを直したい(–amend)
「コミット内容は正しいけれどメッセージをtypoした」という軽微なケースはgit commit --amendが最適です。コミットを作り直すのではなく、直前のコミットを書き換えます。
# 直前のコミットメッセージをエディタで編集 git commit --amend # メッセージを直接指定して書き換える git commit --amend -m "正しいコミットメッセージ" # ファイル追加を忘れたときは、add してから --no-edit で上書き git add forgotten_file.py git commit --amend --no-edit
注意:--amendはSHAが変わるため実質的に履歴の書き換えです。push前ならそのままgit pushできますが、push済みの場合はgit push --force-with-leaseが必要になります。共有ブランチではメッセージ修正でもrevertで新しいコミットを追加する方が安全です。
コミットメッセージ修正を詳しく知りたい場合は、【Git】コミットメッセージの変更方法も参考になります。
push済みのコミットを安全に取り消す(revert)
リモートにpush済みのコミットや、他の開発者が既に取得しているコミットを取り消すときはgit revertが正解です。履歴を改変せず、対象コミットの変更を打ち消す新しいコミットを追加します。他メンバーのローカルと衝突しないため、共有ブランチで安全に使えます。
# 直前のコミットを打ち消す git revert HEAD # 特定のコミット(SHA指定)を打ち消す git revert a1b2c3d # 複数コミットをまとめて打ち消す(範囲指定) git revert a1b2c3d^..f4e5d6a # コミットを作らず、変更だけ適用する(自分でまとめてコミットしたい場合) git revert --no-commit HEAD~3..HEAD git commit -m "revert: 直近3コミットの変更を打ち消し" # マージコミットを取り消す場合は -m で残す親を指定 git revert -m 1 <マージコミットSHA>
ポイント:revert実行中にコンフリクトが起きたら、git statusで衝突ファイルを確認 → 手動で修正 → git add → git revert --continueで続行します。途中で中止するならgit revert --abortです。
マージコミットの取り消しには注意点が多いため、詳細は【Git】mergeコミットを取り消して履歴を元に戻す方法を参照してください。
複数コミットをまとめて取り消す
直近N件のコミットをまとめて取り消したい場合は、HEADからの相対指定か、戻したいコミットのSHAを直接指定します。
# HEADから3件分のコミットを取り消す(変更はワーキングツリーに残る) git reset HEAD~3 # 3件分を完全に破棄 git reset --hard HEAD~3 # 特定のコミットの直前まで戻す(そのSHAに戻る) git reset --hard a1b2c3d # インタラクティブに選んで取り消す・まとめる(途中のコミットだけdropしたい等) git rebase -i HEAD~5
git rebase -iは起動後のエディタでpickをdropに変えれば特定のコミットだけピンポイントで削除でき、squashにすれば隣のコミットに統合できます。特定のコミットまで戻したい場合の詳細は【Git】特定のコミットまで戻す方法、pushしてしまった後の取り消しは【Git】push を取り消す方法に専用解説があります。
誤って消したコミットをreflogで救う
git reset --hardで大事な変更を消してしまった、間違ったコミットまで戻してしまった——そんなときはgit reflogで救済できる可能性があります。Gitは約90日間、HEADの移動履歴をローカルに保持しています。
# HEADの移動履歴を一覧表示
git reflog
# 出力例:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# f4e5d6a HEAD@{1}: commit: 消したくなかった大事な修正
# 9876543 HEAD@{2}: commit: その前の作業
# 消してしまったコミットのSHA(例: f4e5d6a)を指定して復元
git reset --hard f4e5d6a
# あるいは HEAD@{N} 記法でも指定可能
git reset --hard HEAD@{1}
ポイント:reflogは「ローカルリポジトリ上でGitが認識したHEADの動き」を記録しています。削除直後であればほぼ確実に救済できるので、--hardで失敗したと気づいたら他の操作をする前にgit reflogを確認してください。
reset の3つのモードを比較する
違いを整理しておくと、どれを使うべきか瞬時に判断できます。「HEADの移動」「indexの変更」「ワーキングツリーの変更」の3階層のどこまで巻き戻すかが違いです。
この違いを押さえると、「変更を残したいかどうか」「ステージに戻したいか」の2軸ですぐに選べるようになります。revertとの使い分けについては【Git】revertとresetの違いと使い分けで詳しく解説しています。
やってはいけない落とし穴
コミット取り消しで現場が混乱する代表的な失敗パターンです。事前に頭に入れておくだけで事故を防げます。
共有ブランチで reset + force push する
mainやdevelopなど複数人が触るブランチでgit reset --hardを使い、git push --forceすると、他メンバーのローカルに残っていたコミットが消えたり、ビルドが壊れたりします。共有ブランチで取り消すならrevertを使うこと。
未コミットの作業を残したまま –hard する
編集中のファイルがあるままgit reset --hardを実行すると、未コミットの変更がすべて消えて戻せなくなります(reflogにも残らない)。迷ったらgit stashで退避してから実行しましょう。
push済みを –amend して単純な git push する
push後にgit commit --amendするとローカルとリモートで履歴が食い違い、普通のgit pushはnon-fast-forwardで拒否されます。強制pushが必要な場面ではgit push --force-with-leaseを使い、単純な--forceは避けてください(他人のpushを上書きする事故が起きます)。
reflog の期限を過ぎた後に気づく
reflogはデフォルト90日で自動clean upされます。--hardで消した後に数ヶ月経って復元しようとしても手遅れです。重要な作業はこまめにpushするか、ブランチを切って残しておくのが安全策です。
merge コミットを何も考えずに revert する
マージコミットに対しては-m <親番号>オプションが必須です。指定しないと「どちらの親を基準に戻すか」が決まらずエラーになります。詳細はmergeコミットの取り消しガイドを参照。
実践:よくあるシナリオと手順
シナリオ① 機密情報を誤ってコミットしたがまだpushしていない
まず該当のコミットを取り消し、機密情報を除いてから再コミットします。
# コミットは取り消し、変更は手元に残す git reset --mixed HEAD~1 # 機密ファイルを .gitignore に追加 echo "config/secret.env" >> .gitignore # 機密ファイルを除外して再コミット git add -A git commit -m "feat: 設定ファイルの追加(secret.envは除外)"
シナリオ② push済みコミットを打ち消したい
履歴は残したまま、そのコミットの変更だけを元に戻す形が安全です。
# 打ち消したいコミットのSHAを確認 git log --oneline # revertで打ち消しコミットを作成 git revert a1b2c3d # 打ち消しコミットをpush git push origin main
シナリオ③ 直近3コミットを1つにまとめたい
reset --softで3件まとめて取り消し、1件に再コミットすると簡単です。
# 直近3件を取り消し、変更はステージに残す git reset --soft HEAD~3 # まとめた1つのコミットを作成 git commit -m "feat: 認証機能を追加(旧3コミットを統合)"
より細かく選び直したい場合はgit rebase -i HEAD~3でpick/squash/dropを指定します。
よくある質問
reset、push済みや共有ブランチならrevertが基本です。resetは履歴を書き換え、revertは打ち消しコミットを追加するという点で根本的に違います。HEAD~Nは「N個前の先祖」、HEAD^Nは「N番目の親」を指します。マージコミットで2つの親を区別したいときだけ^系を使います。git reflogで復元できます(90日以内)。ただし未コミットの変更(addもしていない編集中のファイル)は--hardで完全に失われます。不安なら先にgit stashで退避してから実行するのが安全です。git statusで衝突ファイルを確認 → 手動で編集 → git add → git revert --continueで完了。中止したい場合はgit revert --abortで元に戻せます。git push --force-with-leaseで安全に強制pushできます。これは「リモートが自分の想定通りの状態なら」強制するオプションで、他人のpushを知らずに上書きする事故を防げます。共有ブランチではrevertに切り替えてください。関連記事
- 【Git】revertとresetの違いと使い分け — 概念の違いを深掘り
- 【Git】特定のコミットまで戻す方法 — 任意のSHAまで戻す詳細手順
- 【Git】push を取り消す方法 — push済みコミットへの対処
- 【Git】コミットメッセージの変更方法 — amendの詳しい使い方
- 【Git】add の取り消し方法 — ステージングだけ戻したいとき
- 【Git】mergeコミットを取り消して履歴を元に戻す方法 — マージ専用の取り消し手順
- 【Git】特定のファイルだけ前のコミットに戻す方法 — 部分リストア
- 【Git】ローカルでだけ動作確認したいときの一時的なコミット&巻き戻し方法 — 一時コミットの巻き戻し
まとめ
- 取り消し前に必ず
git statusとgit log --onelineで現状把握 - 未pushなら
reset系:--softは変更保持、--mixedはステージ解除、--hardは完全破棄 - push済み・共有ブランチなら
revertで打ち消しコミットを追加する - メッセージ修正・ファイル追加忘れは
git commit --amendが便利(未pushのみ) - 誤って
--hardしてもgit reflogで救済できる可能性がある - 共有ブランチでのforce pushと
--amendはチーム全体の事故になりやすいので避ける
コミットの取り消しは「何を」「どこまで」戻したいかを意識すれば、怖いコマンドではなく日常的に使える便利な道具になります。今回の判断表を手元に置き、状況に応じた最小限の取り消しで安全にGitを使いこなしましょう。

