git reset --hard
は、リポジトリを過去の特定の状態に 完全に戻す ための強力なコマンドです。しかし、その強力さゆえに作業内容を失う危険性も伴います。
このコマンドの目的、一般的なエラーとその対処法、そして万が一の場合の復旧方法について詳しく解説します。
git reset --hard
の目的と動作git reset --hard
は、以下の3つの要素を すべて 指定したコミットの状態に書き換えます。
git add
で追加された、次のコミットの候補となるファイルの状態つまり、指定したコミット以降に行ったすべての変更(コミット、ステージング、ファイル編集)がきれいさっぱり消え去ります。
# 直前のコミットを取り消し、その変更内容も破棄する git reset --hard HEAD~1
# <commit-hash> の状態に完全に戻る git reset --hard <commit-hash>
# リモートの最新情報を取得 git fetch origin # ローカルのmainブランチをリモートのmainブランチと完全に一致させる git reset --hard origin/main
⚠️ 注意
git reset –hard は、コミットしていない変更(ワーキングディレクトリ内の変更)を復元不可能な形で削除します。実行する前に git status で状態を確認し、必要な変更は git stash などで一時退避させることを強く推奨します。
fatal: ambiguous argument '<commit>': unknown revision or path not in the working tree.
HEAD~1
を指定)が原因です。git log
や git branch -a
を実行し、正しいコミットハッシュやブランチ名を確認します。error: you have unmerged paths.
git merge
や git rebase
の途中でコンフリクト(競合)が発生し、未解決のファイルが残っている状態です。Gitは、データの損失を防ぐため、コンフリクトが解決されるまで reset
のような危険な操作を許可しません。git status
でコンフリクトしているファイルを確認します。<<<<<<<
, =======
, >>>>>>>
のマーカーを参考にコードを修正します。git add <解決したファイル>
で解決したことをGitに伝えます。git commit
を実行してマージを完了させます。git reset --hard
を実行します。git merge --abort
git reset --hard
でコミットを消してしまっても、すぐに諦める必要はありません。Gitは、コミットされた変更の履歴を一定期間、内部的に保持しています。この履歴(reflog)を利用して、失われたコミットを復元できます。
git reflog
を使った復元の手順git reflog
(reference log) は、HEAD
が過去にどのコミットを指していたかの移動履歴を表示するコマンドです。
例:間違えて reset --hard
してしまった状況
# 現在のコミット履歴 $ git log --oneline a1b2c3d (HEAD -> main) feat: すごい機能を追加 d4e5f6g docs: ドキュメントを更新 h7i8j9k fix: 軽微なバグを修正 # あ、間違えてコミットを1つ消してしまった! $ git reset --hard HEAD~1 HEAD is now at d4e5f6g docs: ドキュメントを更新
$ git reflog d4e5f6g (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1 a1b2c3d HEAD@{1}: commit: feat: すごい機能を追加 <-- これが復元したいコミット! d4e5f6g HEAD@{2}: commit: docs: ドキュメントを更新 ...
reflog
の出力を見ると、reset
を実行する直前(HEAD@{1}
)に a1b2c3d
というコミットがあったことがわかります。# コミットハッシュを指定して復元 $ git reset --hard a1b2c3d # または、reflogのエイリアスを指定して復元 # $ git reset --hard HEAD@{1}
$ git log --oneline a1b2c3d (HEAD -> main) feat: すごい機能を追加 d4e5f6g docs: ドキュメントを更新 h7i8j9k fix: 軽微なバグを修正
最も重要な注意点: この方法で復元できるのは、一度でもコミットされた変更のみです。コミットされていない(ワーキングディレクトリ上やステージングエリアにしかなかった)変更は
git reflog
にも記録されないため、復元できません。