未加-r参数时git rm -f ../*.py为何递归删除文件?
为什么
git rm -f ../*.py会删除子目录中的文件? 核心原因:通配符的处理主体不同
- 常规bash的
rm命令:*.py这类通配符由shell负责展开。当你在dir1目录执行rm -f ../*.py时,shell会先扫描../目录,把../*.py展开成该目录下所有后缀为.py的具体文件名(比如../script0_delete_me.py),随后rm仅处理这些明确的文件,不会触及子目录内容。 git rm命令:通配符由Git自身解析,而非shell。Git会将../*.py理解为「仓库中所有文件名匹配*.py的跟踪文件」——匹配规则基于文件在仓库中的完整路径的文件名部分,而非当前目录的相对路径范围。
结合你的复现场景拆解
在你的测试流程中:
- 将
d.py移动到u/d.py后,Git跟踪的文件路径为u/d.py - 当你在
u目录执行git rm -f ../*.py时,Git未让shell展开通配符,而是自行解析规则:- Git从仓库根目录出发,遍历所有跟踪文件,只要文件名符合
*.py就会被选中。u/d.py的文件名是d.py,完全匹配规则,因此被删除。 - 命令中的
../仅代表当前目录的上级路径,但Git的通配符匹配不受该相对路径限制,它会扫描整个仓库的文件名。
- Git从仓库根目录出发,遍历所有跟踪文件,只要文件名符合
如何避免这种情况?
如果只想删除上级目录下的.py文件,需要让shell先展开通配符,再传递给git rm,比如:
git rm -f ../*.py # 或者直接指定具体文件名,彻底避免通配符歧义 git rm -f ../script0_delete_me.py ../script1_delete_me.py
(注:若上级目录无匹配的.py文件,shell会把../*.py原样传给Git,仍会触发Git的通配符解析,因此直接指定文件名是更稳妥的方式)
对比验证
你提到常规rm不会出现这个问题,正是因为shell先完成了通配符展开,rm拿到的是明确的上级目录文件路径,自然不会触及子目录里的内容。
内容的提问来源于stack exchange,提问作者Ralph
相关产品推荐
相关产品推荐

