Restoring deleted files in Git in Mandarin
復原 Git 誤刪除的檔案
復原方法
方法一:透過 Fork 右鍵選單
使用 Fork Git 客戶端軟體,在歷史紀錄中找到刪除檔案的 commit。
- 右鍵點擊被刪除的檔案
Deleted.file。 - 選擇 Reset File to,再依手上的 commit 選擇下列項目。
State at Commit...:還原到指定 commit 中的檔案版本。選擇檔案仍存在的 commit。State Before Commit...:還原到指定 commit 之前的狀態。如果選到的是刪除檔案的 commit,可用此選項取回刪除前的版本。
方法二:使用命令列
請從 Git 專案根目錄執行。檔案路徑的大小寫與目錄層級須和來源 commit 裡的路徑一致。若同一路徑已有未提交的修改,請先備份,因為還原會覆蓋該檔案。
檔案仍存在於目前的 HEAD
如果檔案是在本機刪除,且目前的 HEAD 仍有這個檔案,可以直接從 HEAD 取回:
git restore --source=HEAD -- 'sub_folder/Deleted.file'
已知檔案仍存在的 commit
把 <commit_hash> 換成檔案仍存在時的 commit hash。例如,若手上的 commit 是新增這個檔案的那一筆,就直接使用該筆 commit:
git restore --source='<commit_hash>' -- 'sub_folder/Deleted.file'
只知道刪除檔案的 commit
一般只有一個父提交的情況下,在刪除檔案的 commit hash 後加上 ^,即可從刪除前的版本取回檔案:
git restore --source='<commit_hash>^' -- 'sub_folder/Deleted.file'
如果刪除發生在合併提交,^ 指第一個父提交。請先確認要取回的版本在哪一個父提交。
確認結果並視需要加入暫存區
上述 git restore --source 指令會寫回工作目錄。先確認檔案內容與 Git 狀態:
git status --short -- 'sub_folder/Deleted.file'
如果要把復原的檔案納入下一次提交,再將它加入暫存區:
git add -- 'sub_folder/Deleted.file'
使用較舊版本的 Git
如果 Git 版本尚未提供 git restore,可以用 git checkout 指定來源與檔案路徑。這種寫法會同時更新工作目錄和暫存區:
git checkout HEAD -- 'sub_folder/Deleted.file'
git checkout '<commit_hash>' -- 'sub_folder/Deleted.file'
依來源擇一執行。第二行的 <commit_hash> 要換成檔案仍存在時的 commit hash。
方法三:從 Local Changes 還原
如果檔案還在 Fork 的 Local Changes 裡顯示為已刪除:
- 點左側的 Local Changes。
- 找到被刪除的檔案。
- 右鍵選擇 Discard Changes。
常見問題
很久以前刪除的檔案,要怎麼找到 commit?
如果記得檔名,但忘了目錄,可以搜尋各個本機可見分支與其他 Git 參照的歷史,並列出符合的提交和路徑:
git -c core.quotePath=false log --all --full-history --name-status -- ':(glob)**/Deleted.file'
:(glob) 啟用 glob 路徑比對。**/ 可匹配零層或多層目錄,* 可匹配單一路徑元件中的字元。
如果不確定檔名大小寫,可以加上 icase:
git -c core.quotePath=false log --all --full-history --name-status -- ':(glob,icase)**/deleted.file'
結果中的 A 表示新增,M 表示修改,D 表示刪除。找到所需版本後,用結果中顯示的完整路徑還原。若選到的是刪除紀錄,請依「只知道刪除檔案的 commit」的方式操作。
為什麼 git show HEAD --name-only 找不到檔案?
git show HEAD --name-only 顯示的是 HEAD 那筆提交的變動清單。檔案可能仍存在於 HEAD,只是這筆提交沒有修改它。
如何確認檔案目前在哪裡?
檢查工作目錄中是否有這個檔案:
find . -type f -name 'Deleted.file'
檢查目前的 HEAD 快照是否包含這個路徑:
git -c core.quotePath=false ls-tree -r --name-only HEAD -- 'sub_folder/Deleted.file'
也可以把 HEAD 換成想檢查的 commit hash。
為什麼中文檔名顯示成反斜線和數字?
Git 可能會將中文路徑顯示為跳脫字元。可以對單次指令設定 core.quotePath=false,用來確認實際檔名:
git --no-pager -c core.quotePath=false show --name-only --format= '<commit_hash>'
執行還原時,請使用實際檔名。若要查看某個路徑是否存在於該 commit 的快照,可以使用上一節的 git ls-tree。
參考資料
- Git 官方文件 - git-restore
- Git 官方文件 - git-log
- Git 官方文件 - git-ls-tree
- How to Restore a Deleted File in Git - git-tower
- Recovering Deleted Files in GitHub - Rewind
- Recovering Deleted Files From Your Git Working Tree - Smashing Magazine
- Advanced Git Log - Atlassian
- Git's database internals III: file history queries - GitHub Blog