Gitでコミットしてしまった後に「やり直したい」と思う場面は多くあります。コミットメッセージを間違えた、余分なファイルを含めてしまった、作業途中でコミットしてしまったなど、状況はさまざまです。
本記事では、git commit の取り消し・修正に使う git reset と git commit --amend を中心に、soft / mixed / hard の違いや事故を防ぐ注意点まで整理します。
よく使うコマンド一覧
まず、コミット取り消し・修正でよく使うコマンドをまとめます。詳細は各セクションで解説します。
# 直前コミットを取り消し(変更はステージングに残す)
git reset --soft HEAD^
# 直前コミットを取り消し(変更はワーキングツリーに残す)
git reset --mixed HEAD^
git reset HEAD^ # --mixed がデフォルト
# 直前コミットを取り消し(変更ごと完全に削除)
git reset --hard HEAD^
# 2つ前に戻す場合
git reset --hard HEAD~2
# 特定のコミットまで戻す
git reset --hard <コミットID>
# 直前コミットのメッセージだけ修正
git commit --amend -m "新しいメッセージ"
# 直前コミットにファイルを追加してやり直す
git add 追加ファイル
git commit --amend --no-edit
1. git reset とは
git reset は、HEADの位置(コミット履歴のポインタ)を指定したコミットまで移動させるコマンドです。移動先を HEAD^(直前のコミット)にすることで、直前のコミットを取り消せます。
# 基本的な書き方
git reset [オプション] <戻り先>
# HEAD^ : 直前のコミット(HEAD~1 と同じ意味)
# HEAD~2 : 2つ前のコミット
# <コミットID> : 特定のコミット
オプションによって、取り消したコミットの変更内容をどこに残すかが異なります。
2. reset –soft / –mixed / –hard の違い
3つのオプションの違いを表で整理します。
| オプション | コミット | ステージング(インデックス) | ワーキングツリー(ファイル) |
|---|---|---|---|
--soft | 取り消す | そのまま残る | そのまま残る |
--mixed(デフォルト) | 取り消す | 取り消す | そのまま残る |
--hard | 取り消す | 取り消す | 取り消す(削除) |
2-1. –soft:コミットだけ取り消す
コミットを取り消しつつ、変更内容はステージング済みの状態で残します。「コミットメッセージを直したい」「複数のコミットをまとめて1つにしたい」ときに使います。
# 直前コミットを取り消し(変更はステージング済みのまま)
git reset --soft HEAD^
実行後は git status で確認すると、変更ファイルが「Changes to be committed」(コミット予定)の状態になっています。そのまま git commit -m "正しいメッセージ" を実行すればやり直せます。
2-2. –mixed:コミットとステージングを取り消す(デフォルト)
コミットとステージングを取り消し、変更内容はワーキングツリー(ファイルの変更自体)に残します。--mixed はデフォルトなので省略可能です。「コミット自体をなかったことにして、どのファイルをコミットに含めるか再選択したい」ときに使います。
# 直前コミットを取り消し(変更はワーキングツリーに残る)
git reset HEAD^ # --mixed がデフォルト
git reset --mixed HEAD^ # 同じ意味
実行後は git status で確認すると、変更ファイルが「Changes not staged for commit」(未ステージング)の状態になっています。
2-3. –hard:コミットも変更も完全に取り消す
コミット・ステージング・ファイルの変更すべてを削除します。「そのコミット以降の変更をすべて捨てて元に戻したい」ときに使います。
# 直前コミットを変更ごと完全に取り消す
git reset --hard HEAD^
# 特定のコミットまで完全に戻す
git reset --hard <コミットID>
注意: --hard で取り消した変更はワーキングツリーから削除されるため、元に戻せません。実行前に本当に不要な変更か確認してください。
3. 直前コミットを修正する(git commit –amend)
git commit --amend は、直前のコミットを修正するコマンドです。コミット履歴を1件追加するのではなく、直前のコミットそのものを書き換えます。
3-1. コミットメッセージだけを修正する
コミット内容(ファイルの変更)はそのままで、メッセージだけ変えたいときに使います。
# コミットメッセージを変更する
git commit --amend -m "修正後のコミットメッセージ"
# エディタを開いてメッセージを編集する
git commit --amend
3-2. ファイルも追加してコミットをやり直す
「追加し忘れたファイルがあった」「コミット前に小さな修正を入れたい」という場合は、ファイルをステージングした後で --amend を実行します。
# 追加し忘れたファイルをステージング
git add 追加したいファイル
# メッセージはそのままでコミットをやり直す
git commit --amend --no-edit
# メッセージも変える場合
git commit --amend -m "新しいメッセージ"
--no-edit を付けると、エディタが開かずメッセージをそのまま引き継げます。
3-3. reset –soft との使い分け
| 操作 | 使うコマンド | 用途 |
|---|---|---|
| 直前コミットのメッセージを修正 | git commit --amend | 最速で修正できる |
| 直前コミットにファイルを追加 | git add + git commit --amend | 追加し忘れたときに便利 |
| 複数コミットをまとめたい | git reset --soft HEAD~N | スカッシュ的な用途に向く |
| コミットを完全にやり直したい | git reset --mixed HEAD^ | ファイル変更を残しつつ再構成 |
4. 事故を防ぐ注意点
4-1. –hard は実行前に必ず確認する
git reset --hard で取り消したワーキングツリーの変更は、基本的に復元できません。実行前に git status と git diff で現在の状態を確認する習慣をつけましょう。
# 実行前に状態を確認する
git status
git diff
# それでも戻したい場合
git reset --hard HEAD^
4-2. プッシュ済みのコミットには使わない
git reset や git commit --amend は、コミット履歴を書き換えます。すでにリモートへプッシュ済みのコミットに使うと、他のメンバーのリポジトリとの履歴が食い違い、チームに大きな混乱をもたらします。
# プッシュ前のコミットにのみ使う(ローカルだけに存在するコミット)
git reset --soft HEAD^ # OK:まだプッシュしていない場合
# プッシュ済みの場合は git revert を使う
git revert HEAD # コミット取り消しのコミットを追加(履歴を書き換えない)
4-3. git reflog で誤操作から復元できる
--hard で誤って取り消してしまっても、直後であれば git reflog でコミットIDを確認し、復元できることがあります。
# reflog でコミット履歴を確認
git reflog
# 出力例:
# a1b2c3d HEAD@{0}: reset: moving to HEAD^
# e4f5g6h HEAD@{1}: commit: 作業内容
# ...
# 消えたコミット(e4f5g6h)に戻す
git reset --hard e4f5g6h
git reflog はローカルの操作履歴を記録しているため、--hard で削除したコミットも一定期間は参照できます。
4-4. 作業中のファイルは stash でバックアップ
reset の前に未コミットの作業内容をバックアップしたい場合は git stash を使います。
# 作業中の変更を一時退避
git stash
# reset を実行
git reset --hard HEAD^
# 必要なら退避した変更を戻す
git stash pop
5. よくある疑問
HEAD^ と HEAD~1 は同じ意味か
同じ意味です。HEAD^ は直前のコミット(1つ前)を指します。2つ前は HEAD^^ または HEAD~2、3つ前は HEAD~3 のように書きます。
reset –mixed と reset –soft はどちらを使えばいいか
「コミットをやり直したいが、何をステージするか再選択したい」なら --mixed、「コミットを取り消してすぐにコミットし直す(ファイル選択は変えない)」なら --soft が向いています。迷ったら --mixed(デフォルト)を使えばファイルは消えないので安全です。
git revert と git reset の違いは何か
git reset はコミット履歴を書き換えます。一方 git revert は「取り消しコミット」を新たに追加することで変更を打ち消します。プッシュ済みのコミットを取り消す場合は git revert を使い、履歴を書き換えないのが原則です。
amend したらプッシュできなくなった
git commit --amend はコミット履歴を書き換えるため、プッシュ済みのコミットに使うとリモートとの履歴が食い違い、通常のプッシュが拒否されます。個人ブランチであれば git push --force-with-lease で上書きできますが、チームで使うブランチでは行わないでください。
コミット取り消し後にリモートと同期するには
ローカルでコミットを取り消した後、リモートと同期するには git pull --rebase または git fetch + git reset が必要になる場合があります。個人ブランチでなければ、チームに影響が出るため慎重に判断してください。
まとめ
git commit 取り消し・git reset の使い方をまとめます。
- –soft: コミットだけ取り消し。変更はステージング済みで残るため、コミットをすぐにやり直せる。
- –mixed(デフォルト): コミットとステージングを取り消し。変更はファイルに残るため、git add からやり直せる。
- –hard: コミット・ステージング・ファイル変更すべてを削除。元に戻せないため、実行前に必ず確認する。
- git commit –amend: 直前コミットのメッセージ修正やファイル追加に便利。プッシュ済みには使わない。
- プッシュ済みには git revert: 共有ブランチのコミット取り消しは履歴を書き換えない git revert を使う。
- 誤操作は git reflog で復元: –hard で消しても git reflog からコミットIDを探して復元できる場合がある。

コメント