在 Git 命令行中删除文件是一个常见的操作,但需要注意区分“从工作区删除文件”和“从 Git 仓库中彻底移除文件”两种场景,不同的操作对应不同的命令,且可能涉及暂存区、工作区和仓库历史的状态管理,以下是详细的操作步骤和注意事项。

删除文件的基本操作
如果只是希望从工作区中删除文件,并且同时将删除操作纳入暂存区(即下一次提交时会包含此删除操作),可以使用 git rm 命令,要删除当前目录下的 test.txt 文件,可以执行:
git rm test.txt
执行此命令后,test.txt 文件会从工作区中被删除,并且删除操作会被添加到暂存区,此时运行 git status 会显示 deleted: test.txt,表明该文件已被标记为删除状态,接下来通过 git commit 即可完成删除操作的提交。
如果文件已经被修改过(即工作区中的版本与暂存区或仓库中的版本不同),直接执行 git rm 会报错,此时需要强制删除,使用 -f 选项:
git rm -f test.txt
强制删除会直接覆盖工作区的文件变更,并将其从暂存区移除。

从暂存区移除但保留工作区文件
我们可能希望将文件从暂存区移除(即取消暂存),但保留工作区中的文件,文件已被 git add 添加到暂存区,但后续发现不需要提交该文件,此时可以使用 git rm --cached 命令:
git rm --cached test.txt
执行后,test.txt 文件会保留在工作区,但会被从暂存区移除,运行 git status 会显示 deleted: test.txt (use "git restore --staged <file>..." to unstage),实际上这是 Git 提示文件已被取消暂存,而非物理删除,这种操作常用于误添加文件到暂存区时的回退。
删除目录及子目录中的文件
如果要删除整个目录及其中的所有文件,可以使用 git rm 命令并加上 -r 选项(递归删除):
git rm -r directory_name
删除名为 docs 的目录及其所有内容:

git rm -r docs
同样,如果目录已被修改,需要使用 -f 选项强制删除:
git rm -rf docs
注意:git rm -rf 是一个危险操作,会直接递归删除目录且无需确认,使用时需谨慎,避免误删重要文件。
删除文件后的提交流程
执行 git rm 后,删除操作仅被添加到暂存区,并不会立即生效到仓库历史,需要通过 git commit 提交才能完成最终的删除:
git commit -m "Remove test.txt"
提交后,test.txt 文件会被从 Git 仓库的历史记录中彻底移除(除非使用 git reflog 等工具恢复),其他开发者拉取此提交后,本地对应的文件也会被删除。
误删文件的恢复方法
如果在执行 git rm 后尚未提交,可以通过 git restore 恢复文件:
git restore test.txt
此命令会从暂存区或仓库中恢复文件到工作区,如果已经提交,则需要通过 git revert 撤销提交,或使用 git reflog 找到删除前的提交 ID 并通过 git checkout 恢复。
不同删除操作的区别
以下是常见删除操作的区别总结:
| 操作场景 | 命令 | 工作区文件 | 暂存区状态 | 仓库历史 |
|---|---|---|---|---|
| 删除文件并纳入暂存区 | git rm test.txt |
删除 | 标记删除 | 未变更 |
| 强制删除已修改的文件 | git rm -f test.txt |
删除 | 标记删除 | 未变更 |
| 取消暂存但保留工作区文件 | git rm --cached test.txt |
保留 | 取消暂存 | 未变更 |
| 递归删除目录 | git rm -r directory_name |
删除 | 标记删除 | 未变更 |
| 提交删除操作 | git commit -m "Remove file" |
删除 | 清空 | 标记删除 |
相关问答FAQs
Q1: 如果误删了文件,但尚未提交,如何恢复?
A1: 可以使用 git restore 命令恢复文件,执行 git restore test.txt 会从暂存区或最新提交中恢复 test.txt 到工作区,如果文件已被 git rm --cached 移除暂存区但保留在工作区,则无需操作,文件仍存在。
Q2: 如何彻底从 Git 仓库历史中删除文件(如敏感文件)?
A2: 使用 git filter-branch 或 git filter-repo 工具(需单独安装)可以重写提交历史,彻底移除文件,执行 git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch file_name' --prune-empty --tag-name-filter cat -- --all 会从所有提交中删除 file_name,并强制推送覆盖远程仓库,注意:此操作会修改历史,可能导致分支冲突,需谨慎使用。
