「rmで消したファイルを戻したい」「git rmしてしまった」「削除コミットがpushされた後に復元できるか」——ファイル削除の復旧はGit運用で頻出する相談です。削除の進行度合い(作業ツリー/ステージ/コミット/push)によって使うコマンドが変わり、知らずにgit reset --hardを実行すると別の変更まで消してしまうこともあります。
この記事では、Gitで削除されたファイルを状況別に復元する方法を整理します。git restore(Git 2.23以降の推奨コマンド)とgit checkoutの使い分け、削除コミットの打ち消し、遠い過去のコミットから消えたファイルを拾うgit log --diff-filter=Dの使い方、そして絶対に復元できないケースも含めて実務で役立つ形でまとめます。
この記事で学べること
- 削除の進行度合いに応じた5つの復元パターン
git restoreとgit checkoutの使い分け- 削除コミットを特定する
git log --diff-filter=Dの使い方 - push済み削除を打ち消す
git revertでの安全な復旧 - ディレクトリ丸ごと削除の復元手順
- 「復元不可能なケース」と予防策(未追跡ファイル・削除後の新規編集など)
まず確認:どの段階で消えたかを特定する
最短で正しい復元コマンドに辿り着くには、「削除はどこまで進んでいるか」を切り分けることが重要です。以下のコマンドで状態を確認してからコマンドを選びましょう。
# 作業ツリーとステージの状態を確認 git status # 削除が直近のコミットに含まれているか確認 git log --diff-filter=D --name-only -5 # 特定ファイルに関する全履歴を追う(renameも含む) git log --all --full-history --follow -- <filepath> # ファイルがいつ・どのコミットで削除されたか特定 git log --diff-filter=D --name-only -- <filepath>
ポイント:Git 2.23以降はgit restoreが「ファイル復元専用の安全なコマンド」として推奨されています。git checkoutはブランチ操作と混在して誤用しやすいため、新しく覚えるならrestoreを先に習得すると迷いません。古い環境で使えない場合はcheckoutでも同じことができます。
パターンA:作業ツリーで消しただけ(未ステージ)
エディタやエクスプローラー、rmコマンドでファイルを消したが、git addしていない状態——つまりGit的には「変更しただけ」で、削除はステージングに載っていない状態です。git statusで「deleted:」がChanges not staged for commitの下に表示されます。
# まずは状態確認 git status # → "deleted: sample.txt" が Changes not staged に表示 # Git 2.23以降:restore で作業ツリーを最新コミットから復元 git restore sample.txt # 複数ファイルを一括復元 git restore src/config.js src/utils.js # ディレクトリ配下を再帰的に復元 git restore src/ # 旧コマンド(Git 2.23より前でも動く) git checkout -- sample.txt
ポイント:この段階は最も簡単です。ステージングにもコミットにも削除情報が載っていないので、GitのHEADには元のファイルが残っています。restore一発で元通りになります。
パターンB:ステージに削除を載せた(未コミット)
git rm sample.txtや、rmのあとgit add -Aを実行した状態です。git statusで「deleted:」がChanges to be committedに表示されます。この場合はステージを戻してから作業ツリーに復元する2段階が必要です。
# 状態確認 git status # → "deleted: sample.txt" が Changes to be committed に表示 # restore で ステージ(--staged)と作業ツリー(--worktree)を同時に戻す git restore --staged --worktree sample.txt # 2回に分けても同じ結果 git restore --staged sample.txt # ステージから削除を取り消し git restore sample.txt # 作業ツリーに復元 # 旧コマンドでの対応 git reset HEAD sample.txt git checkout -- sample.txt
–staged と –worktree の使い分け
git restore --staged <file>:ステージだけ戻す(作業ツリーの削除状態は残る)git restore <file>:作業ツリーだけ戻す(ステージの削除は残る)git restore --staged --worktree <file>:両方を一括で戻す(本ケースで推奨)
注意:古い情報でgit reset HEAD <file>だけを紹介している記事もありますが、これでは作業ツリーのファイルは戻りません。ステージ解除+作業ツリー復元の両方が必要です。
パターンC:削除をコミットしたが未push
誤って削除を含めてコミットしたが、まだpushしていない状態です。選択肢は2つあります:コミット全体を取り消すか、削除されたファイルだけを1つ前のコミットから復元して新しいコミットを作るか。他の変更も同じコミットに含まれているなら後者が安全です。
# 直前のコミットを取り消し、変更はステージに残す git reset --soft HEAD~1 # ステージから削除だけ取り消して作業ツリーに復元 git restore --staged --worktree sample.txt # 他の正しい変更を再コミット git commit -m "feat: 必要な変更だけを再コミット"
# 1つ前のコミット(HEAD~1)からファイルを取り出して追加 git checkout HEAD~1 -- sample.txt # Git 2.23以降の restore 版 git restore --source HEAD~1 -- sample.txt # ステージングされるので、戻したことをコミットする git commit -m "revert: sample.txt を復元"
ポイント:選択肢2の方が「削除コミットの履歴は残しつつ、復元した事実も履歴に残す」形になるため、チーム開発では追跡しやすく推奨です。個人ブランチで履歴を綺麗にしたい場合は選択肢1+git commit --amendも選択肢です。
パターンD:削除コミットがpush済み
削除コミットが既にリモートに公開されている場合は、履歴を書き換えずにgit revertで打ち消しコミットを追加するのが原則です。共有ブランチでも安全に使えます。
# 削除コミットのSHAを特定 git log --diff-filter=D --name-only -10 # 出力例: # a1b2c3d Delete obsolete config # config/old.yml # config/obsolete.yml # そのコミット全体を打ち消す(削除されたファイルが全部復活) git revert a1b2c3d # 打ち消しコミットをpush git push origin <branch>
削除コミットの中から特定ファイルだけを復元する
削除コミットには他のファイル削除も含まれているが「sample.txtだけ復元したい」場合、revertではなくcheckout/restoreで個別に取り出します。
# 削除コミットの1つ前(^は親を意味する)からファイルを取り出す git checkout a1b2c3d^ -- sample.txt # restore 版 git restore --source a1b2c3d^ -- sample.txt # ステージされた状態になるのでコミット git commit -m "restore: sample.txt を復元" git push origin <branch>
push後の打ち消し全般はpushを取り消す方法、コミット取り消しの全体像はコミットの取り消し方も参考になります。
パターンE:何コミットも前に削除されたファイルを拾う
「プロジェクトに昔あったはずのファイルがどこかで消えた」「でもいつどこで消えたか分からない」——そんなときはgit log --diff-filter=Dを使って削除の痕跡を辿ります。ファイル名を覚えていれば--followでリネーム含め追跡できます。
# 削除が含まれるコミットだけを一覧(直近から) git log --diff-filter=D --name-only --oneline # 特定ファイル名を含む削除コミットを検索 git log --diff-filter=D --name-only --oneline -- sample.txt # ファイル名をうろ覚えの場合:履歴全体から文字列検索 git log --all --diff-filter=D --name-only -- "*config*" # リネームされている可能性も辿る git log --all --full-history --follow -- path/to/old_name.txt # 削除コミットのSHAを特定したら、1つ前からファイルを取り出す git checkout <削除SHA>^ -- sample.txt # 取り出したファイルをコミット git add sample.txt git commit -m "restore: sample.txt を復元"
役立つオプション早見
--diff-filter=D:削除されたファイルを含むコミットだけに絞る--name-only:各コミットで変更されたファイル名を表示--follow:リネームを跨いで履歴を追跡--all:全ブランチ・タグの履歴を対象にする--full-history:単純化された履歴ではなく完全履歴を表示
ファイル名不明でも中身のキーワードで探す
# コミット履歴全体から特定の文字列を含むコミットを検索 git log -S "DATABASE_URL" --all --source --oneline # 削除と組み合わせる git log -S "DATABASE_URL" --all --diff-filter=D --oneline # そのコミットの差分を見て、どのファイルに含まれていたか確認 git show <SHA>
ポイント:-Sは「ファイルに指定文字列が追加/削除されたコミット」を探すpickaxe(ピックアックス)検索です。正規表現で探したいときは-G "pattern"を使います。削除されたファイルの内容を思い出せれば、ファイル名が分からなくても発掘できます。
ディレクトリ全体を復元する
フォルダ丸ごと削除したときも、基本は同じです。ディレクトリパスを指定すれば配下のファイルが一括で復元されます。
# 作業ツリーの未ステージ削除を戻す git restore src/legacy/ # ステージング済みの削除を戻す git restore --staged --worktree src/legacy/ # 過去のコミットから復元(削除コミットSHAの1つ前を使う) git checkout <削除SHA>^ -- src/legacy/ # push済み削除ならrevert(削除コミット全体を打ち消す) git revert <削除SHA>
注意:Gitは「空のディレクトリ」を管理しません。ファイルが1つも含まれないディレクトリは復元不可です。空でも残したい場合は慣例で.gitkeepという空ファイルを置きます。
復元できないケースと対処
一度もcommitしていないファイル
Gitにgit add・git commitされていない未追跡ファイルをrmで消した場合、Gitには情報が残っていないため復元できません。OSのゴミ箱・エディタの自動バックアップ・IDEのローカル履歴(VS Code/IntelliJ)を探してください。
IDEのローカル履歴を使う
- VS Code / Cursor:Timelineビューまたは
Local History拡張で過去バージョンを確認 - JetBrains(IntelliJ/WebStorm):右クリック→
Local History→Show History - Windows:ファイルエクスプローラーのプロパティ→以前のバージョン(シャドウコピー)
- macOS:Time Machineが動いていれば復元可能
git clean -fdx で削除した未追跡ファイル
git cleanは未追跡ファイルを完全削除します。Git履歴には一切残らないため復元はできません。実行前は必ずgit clean -n(dry-run)で対象を確認する習慣を付けましょう。
# まずドライランで対象を確認 git clean -n # 対話モードで1件ずつ確認しながら削除 git clean -i # 本当に削除して良いか確認してから実行 git clean -fd
reflog期限を過ぎたコミット内のファイル
reflogは既定で90日間だけ保持されます。git reset --hardなどで失ったコミットを時間が経ってから拾おうとしても手遅れになる可能性があります。重要な作業はこまめにpushするのが保険になります。
実践:よくあるシナリオ
シナリオ① 間違えて rm -rf してしまった
# 被害状況の確認 git status | head -20 # 未ステージ削除ならカレントディレクトリ以下を一括復元 git restore . # ステージにまで載ってしまっていたら git restore --staged --worktree . # リポジトリのトップレベルから一括復元 git restore "$(git rev-parse --show-toplevel)"
シナリオ② IDEのリファクタリングで誤って消えた
# 直近コミット以降で削除されたファイル一覧 git diff --name-only --diff-filter=D HEAD # 全部HEADから復元 git diff --name-only --diff-filter=D HEAD | xargs git restore --source=HEAD # 一つずつ確認しながら復元 git status git restore src/specific/file.ts
シナリオ③ 古いコミットの設定ファイルを復活させたい
# v1.0.0時点の .env.example を取り出したい git log --all --name-only --follow -- .env.example | head -20 # タグ・ブランチから直接取り出すこともできる git restore --source v1.0.0 -- .env.example # 特定コミットからの取得(HEADの変更は触らない=stagingされる) git checkout v1.0.0 -- .env.example
削除事故を防ぐベストプラクティス
普段から心掛けたいこと
- 大きな変更の前は必ずコミット:復元の起点が増える
- 未追跡ファイルをこまめに
git add:Git管理下に置くと復元可能になる git clean -nで事前確認:未追跡ファイルは消したら戻せない- 定期的にpush:リモートがバックアップになる
- 危険操作前はブランチを切る:分岐させておけば元のブランチが無傷で残る
- IDEのLocal History機能を有効化:Git外の変更も追える
やってはいけない落とし穴
git reset HEAD <file> だけで復元できると思う
旧記事でもよくある誤解です。git reset HEAD <file>はステージから削除を取り消すだけで、作業ツリーには削除状態のファイルが残ります。その後git restore <file>(またはgit checkout -- <file>)で作業ツリーも戻す必要があります。git restore --staged --worktreeなら1コマンドで完結します。
未ステージの削除と勘違いして git reset –hard を使う
1ファイルだけ戻したいときにgit reset --hardを実行すると、他のファイルで進行中の変更まで全部消えます。部分復元はgit restoreを使い、--hardは最終手段です。
git clean の対象を確認せずに実行する
git clean -fdxは.gitignore対象も含めて未追跡ファイルを消去します。node_modulesを消したつもりがビルド成果物や個人メモまで消えた、という事故が起きます。必ず-n(dry-run)で対象を確認するか、-i(対話モード)を使いましょう。
削除コミットを force push で物理的に消そうとする
チーム共有ブランチでは禁じ手です。履歴を書き換えることで他メンバーの環境が壊れるうえ、復元手段としてはrevertの方が安全かつ履歴も追跡しやすい形になります。push済み削除はgit revertで打ち消すのが原則です。
復元後に「ステージされていない」と勘違いする
git checkout <SHA> -- <file>で過去コミットから取り出したファイルは自動的にステージされます。そのあとgit commitするだけで復元完了ですが、「まだaddしないと」と追加でgit addすると重複ステージになるので注意してください。(重複しても害はありませんが、混乱のもとです)
よくある質問
git restoreが推奨です。ファイル復元専用で誤操作が起きにくく、--staged・--worktreeの制御も明確です。古いGitではgit checkoutを使います。git log --all --full-history --diff-filter=D --name-only -- <ファイル名>で削除コミットを特定し、その^(親コミット)からファイルを取り出します。ファイル名不明ならgit log -S "中身のキーワード"で内容から検索できます。git revertで打ち消しコミットを追加し、「戻しました」と明示するのが事故の少ない方法です。履歴を隠したいほど緊急(機密情報など)ならfilter-repoを使いますが、全メンバーの再cloneが必要になります。git show <SHA>:<path> > /tmp/recovered.txtのようにリダイレクトすれば、Git管理外に中身だけ取り出せます。git reflogでブランチ先端のSHAを探し、git checkout <SHA> -- <file>で取り出せます。90日以内なら高確率で救済できます。詳しくは誤ってmaster/mainを削除したときの復旧方法も参考になります。git restore .(未ステージ一括)またはgit restore --staged --worktree .(ステージ+作業ツリー一括)でカレントディレクトリ以下を丸ごと戻せます。コミット済みならgit diff --name-only --diff-filter=D HEAD~1 | xargs git restore --source=HEAD~1のようなパイプ処理も有効です。関連記事
- 【Git】特定のファイルだけ前のコミットに戻す方法 — 削除ではなく「過去の状態に戻す」場合
- 【Git】過去の特定ファイルだけ元に戻す方法 — checkout/restoreの実例集
- 【Git】pull後に意図しないファイル削除が発生したときの復元方法 — pull起因の削除対応
- 【Git】stashした内容を失ってしまったときの復元方法 — stash消失からの救済
- 【Git】pushを取り消す方法 — push済み削除コミットへの対処
- 【Git】コミットの取り消し方 — reset/revert/amendの使い分け
- 【Git】誤ってmaster/mainを削除したときの復旧方法 — ブランチ・HEAD消失系
- 【Git】管理からファイルを外す方法 — 意図的にGit管理を外す手順
まとめ
- 復元コマンドは削除の進行度合い(作業ツリー/ステージ/コミット/push)で決まる
- まずは
git statusとgit log --diff-filter=Dで現状を把握 - Git 2.23以降は
git restoreが推奨(checkoutでも代替可) - ステージ+作業ツリーの両方を戻すなら
git restore --staged --worktreeが1コマンドで便利 - push済み削除は
git revertで打ち消しコミットを追加するのが原則 - 古い削除は
git log --diff-filter=D --followや-S "キーワード"で発掘 - 未追跡ファイルと
git cleanで消えたファイルは復元不可
ファイル削除の復元は、Gitの状態モデル(作業ツリー/ステージ/HEAD/リモート)を理解していれば怖くありません。慌てずgit statusで現状を確認し、削除の進行度合いに応じた適切なコマンドを選ぶ——この基本を押さえれば、ほとんどの削除事故はすぐに元通りにできます。Git管理外のファイル・git clean・reflog期限切れだけは復元不可なので、普段からこまめなgit add・commit・pushを心掛けて予防しましょう。

