HOWTO · Git

如何在 Git 中復原 rm

了解如何復原以 git rm 移除的檔案,無論刪除尚在暫存區還是已提交。選擇安全的 Git 命令,從索引或某個提交還原目標版本。

本頁內容

若要復原 git rm,先確認刪除尚在暫存區還是已經提交。提交之前,從 HEAD 還原該路徑;提交之後,選取包含目標版本的提交,並從該提交還原路徑。Git 可以復原已提交的版本,但無法重建從未提交過的檔案內容。

了解 git rm 變更了什麼

git rm <path> 會從工作樹移除受追蹤的檔案,並將其刪除放入暫存區的索引中。因此,該刪除已準備好包含在下一次提交中。命令 rm 不是 git remove 的別名;rm 是 shell 命令,而 git rm 還會更新 Git 的索引。

當你希望 Git 停止追蹤某個檔案、同時保留其工作樹副本時,使用 git rm --cached <path>。這會將從索引中的移除放入暫存區,並把檔案留在磁碟上。常用於檔案應保留在本機、但不再屬於儲存庫的情況。

在提交前還原刪除

如果刪除已在暫存區,且你需要最後提交的版本,使用 git restore --source=HEAD --staged --worktree -- <path> 從 HEAD 將路徑同時還原到索引和工作樹。使用前先確認你的 Git 安裝提供 git restore。如果不提供,git checkout HEAD -- <path> 會從 HEAD 將該路徑還原到索引和工作樹。

這些命令復原的是已提交的版本,而不是只存在於工作樹中的編輯。先檢查該路徑的任何暫存或本機變更,因為同時還原兩個位置會以選取的版本取代該路徑。若要還原多個路徑,在 -- 之後逐一列出每個路徑。

這個自包含範例會建立一個臨時儲存庫、提交一則筆記、將其移除放入暫存區,然後還原已提交的版本。最後一行是還原後的檔案內容。

set -eu
repo_dir="$(mktemp -d)"
trap 'rm -rf "$repo_dir"' EXIT
cd "$repo_dir"
git init -q
git config user.name "Example User"
git config user.email "example@example.invalid"
printf 'A tracked note.\n' > notes.txt
git add notes.txt
git commit -qm "Add note"
git rm -q notes.txt
if git restore --source=HEAD --staged --worktree -- notes.txt 2>/dev/null; then
  :
else
  git checkout HEAD -- notes.txt
fi
cat notes.txt

預期標準輸出:

A tracked note.

在提交後復原刪除

在提交記錄了刪除之後,選取包含目標檔案版本的提交。然後使用 git restore --source=<commit> --staged --worktree -- <path> 只還原該路徑。如果 git restore 無法使用,使用 git checkout <commit> -- <path>。將 <commit> 和 <path> 換成選取的提交和相對於儲存庫的路徑。

還原單一路徑並不會撤銷刪除它的提交;它會建立一個已放入暫存區的檔案還原,你可以檢視並提交。不要假設 HEAD~1 是正確的來源:可能存在更晚的提交,而緊鄰的前一個提交也可能不包含你需要的版本。

用 Git 歷史尋找較早版本

使用 git log --all -- <path> 檢查變更過該路徑的提交,並找出包含目標版本的那個。git reflog 記錄近期的分支頂端位置,可協助在分支移動(例如重置)後定位提交。它不會另外儲存檔案內容;你選取的提交必須包含你需要的檔案版本。

找到候選提交後,先確認它包含該路徑,然後使用上述命令從候選提交還原該路徑。Git 歷史只在內容已提交時才有幫助。如果檔案從未提交,請改查編輯器備份、系統備份或其他副本。

選擇安全的復原方法

依儲存庫狀態選擇來源:對於未提交的暫存刪除,從 HEAD 還原;對於已提交的刪除,從某個特定的較早提交還原。在提交復原的檔案之前,檢視暫存的差異和工作樹狀態,特別是當同一路徑上還有其他工作時。

避免把 git reset --hard 作為復原單一檔案的慣常方法。它會重置索引和工作樹,可能捨棄無關的未提交變更。從選取的提交還原單一路徑更有針對性。對於多個檔案,將每個路徑提供給還原命令,並在提交前檢視產生的變更。