簡介
命令格式:
git rm --cached <file>
意思:
從Git的 索引(index,暫存區) 中移除文件,但保留工作區中的實際文件。
也就是説:
- 文件仍然留在硬盤(工作區);
- 但不再被
Git跟蹤(tracked)。
<file>...:要移除的文件或目錄路徑。可以指定多個文件,或使用通配符(如 *.log)。
常用選項:
--cached:僅從索引移除(必須使用)。-r或--recursive:遞歸移除目錄及其內容(如果指定目錄)。-f或--force:強制移除,即使暫存內容不匹配分支tip或磁盤文件。-q或--quiet:安靜模式,抑制輸出。--ignore-unmatch:如果文件不在索引中,繼續執行而不報錯。
三大區域
Git 有三層結構:
| 層級 | 名稱 | 説明 |
|---|---|---|
| Working Directory | 工作區 | 真實存在的文件 |
| Index (Staging Area) | 暫存區 | 下次提交的快照 |
| Repository | 倉庫 | 提交的歷史記錄(.git/objects) |
當執行:
git add file.txt
文件被添加到 index(暫存區)。
當執行:
git commit
暫存區內容被保存為新的 commit(快照)。
而:
git rm --cached file.txt
是從暫存區刪除這個文件的記錄(同時停止跟蹤),但不刪除工作區文件。
效果演示
假設當前有一個文件:
$ echo "test" > test.log
$ git add test.log
$ git commit -m "add log file"
現在 test.log 已經被 Git 跟蹤。
如果加了 .gitignore:
*.log
這時 .gitignore 對 test.log 不起作用,因為它已經在倉庫歷史中被跟蹤了。
解決辦法:
git rm --cached test.log
執行結果:
rm 'test.log'
然後執行:
git status
會顯示:
deleted: test.log
Git 認為你要“從版本控制中刪除它”,但文件還在硬盤上。
接着提交一次:
git commit -m "Stop tracking test.log"
最終效果:
test.log在倉庫中被移除(不再跟蹤)- 本地文件還在(不會被刪除)
.gitignore會開始對它生效(以後不會再被加入)
常見用法場景
| 場景 | 命令 | 説明 |
|---|---|---|
讓 .gitignore 生效(停止跟蹤) |
git rm --cached <file> |
典型用途 |
| 停止跟蹤整個目錄 | git rm -r --cached <dir> |
遞歸地移除目錄 |
| 停止跟蹤所有已跟蹤但應忽略的文件 | git rm -r --cached . + git add . |
重置索引(慎用) |
| 移除緩存但不刪物理文件 | git rm --cached |
保留文件在工作區 |
與 git rm(不帶 --cached)的區別
| 命令 | 移除暫存區 | 刪除工作區文件 | 説明 |
|---|---|---|---|
git rm file |
✅ | ✅ | 刪除文件並記錄提交(徹底刪) |
git rm --cached file |
✅ | ❌ | 僅從 Git 跟蹤中移除(保留物理文件) |
查看哪些文件仍在索引中
可以用以下命令查看:
git ls-files
移除緩存前:
test.log
執行 git rm --cached test.log 後:
(test.log 不再出現)
高級用法
批量移除已跟蹤但應忽略的文件
# 查看所有已跟蹤的文件
git ls-files
# 結合 grep 找到特定模式的文件並移除
git ls-files | grep '\.tmp$' | xargs git rm --cached
# 或者使用 find 命令
find . -name "*.log" -exec git rm --cached {} \;
從所有提交歷史中完全刪除文件
如果文件包含敏感信息且已經推送到遠程,需要從歷史中完全刪除:
# 1. 使用 filter-branch 從所有提交中刪除文件
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch secrets.txt' \
--prune-empty --tag-name-filter cat -- --all
# 2. 強制推送到遠程
git push origin --force --all
實際場景案例
遷移到大文件存儲 (Git LFS)
# 發現大文件已被普通 Git 跟蹤
git ls-files | grep -E '\.(psd|ai|zip)$'
# 從普通 Git 跟蹤中移除
git rm --cached design.psd large-video.mp4
# 配置 Git LFS
git lfs track "*.psd" "*.mp4"
# 重新添加文件(現在通過 LFS 跟蹤)
git add design.psd large-video.mp4
git commit -m "Migrate large files to LFS"
清理誤提交的依賴目錄
# 誤提交了 node_modules
git add . # 不小心包含了 node_modules
# 從 Git 中移除
git rm --cached -r node_modules/
# 確保 .gitignore 包含 node_modules
echo "node_modules/" >> .gitignore
# 提交
git add .gitignore
git commit -m "Remove node_modules from version control"
分離環境配置文件
# 開發環境配置文件不應提交
git rm --cached config/dev.json
# 創建模板文件供其他開發者使用
cp config/dev.json config/dev.json.template
git add config/dev.json.template
echo "config/dev.json" >> .gitignore
git add .gitignore
git commit -m "Make dev config local only"
注意事項
- 不會刪除物理文件(只改
Git索引); - 必須提交一次,遠程倉庫才會真正刪除它;
- 如果多人協作,建議在
.gitignore裏同步寫入規則,防止其他人再次添加; - 想恢復跟蹤,只需:
git add <file>
git commit -m "track file again"
底層原理
git rm --cached 的工作機制涉及 Git 的核心數據結構:
索引(Index/Staging Area):
Git的索引是一個二進制文件(.git/index),記錄暫存的文件狀態(內容哈希、模式、路徑)。--cached只修改索引,而不觸及工作目錄或對象數據庫(objects)。
安全檢查:
Git要求暫存內容與分支tip(最新提交的樹對象)或磁盤文件匹配。這防止你意外移除有本地修改的文件。- 如果不匹配,
Git報錯:error: path 'file.txt' is unmerged或did not match any files。 - 使用
-f繞過此檢查。
對象影響:
- 移除後,下次提交的樹對象(
tree object)將不包含該文件。 - 歷史記錄不受影響:舊提交中仍保留文件(通過
Blob對象)。 - 與快照機制相關:
Git存儲完整快照,但移除隻影響未來快照。
與 git add 的反向:
git add將工作目錄文件添加到索引。git rm --cached是其逆操作,從索引移除。