我正在尝试git的一些示例说明并遇到了这个特殊的情况,当我们做git rm *
时,它不会在第一次尝试时删除.*
文件。为什么会这样?
mkdir -p test_repo1/folder && cd test_repo1
touch .testfile1 .testfile2 testfile3 folder/testfile4 folder/.testfile5
git init && git add . && git commit -m "test commit"
如果现在我按照以下方式执行git rm
,我必须第二次删除所有文件
$ git rm -r *
rm 'folder/.testfile5'
rm 'folder/testfile4'
rm 'testfile3'
$ git rm -r *
rm '.testfile1'
rm '.testfile2'
为什么git在第一次尝试时不删除所有文件?另外,为什么仅对具有repo root的文件发生这种情况?
有趣的是,如果我只有那些.testfiles
,那么git会在第一次尝试中删除它们。
我正在使用git版本1.7.9.5
通配符由shell扩展,默认情况下,扩展在大多数shell中不包括点文件。
所以当git
执行时,第一个命令就变成了
git rm -r folder testfile3
第二个可能是文字
git rm -r *
然后git
自己扩展。
由于remarked by Keith,一次性删除所有内容,阻止shell扩展通配符,以便git
第一次进行扩展。这可以使用双引号或单引号,或者在星号前使用反斜杠来完成。我倾向于选择单引号:
git rm -r '*'
当你运行git rm *
时,你实际上是使用shell的globbing规则将参数传递给git-rm(1)。默认情况下,许多shell不包含隐藏文件(例如带有前导点的文件)。在Bash中,您可以使用dotglob和GLOBIGNORE更改globbing规则。例如:
# set dotglob
shopt -s dotglob
git rm *
# unset dotglob
shopt -u dotglob
# Run git within a modified environment that includes GLOBIGNORE.
GLOBIGNORE='.git' git rm *
正如用户1283885在评论中指出的那样,shell第一次扩展了*
。
第二次删除点文件的原因是,一旦没有要匹配的文件,shell就会将文字星号作为参数(取决于你的shell,至少有一个变量错误),然后git自己做匹配。
请注意,正确的语法应该是git rm -r .
('dot')
更令人担忧的是git rm -r
(空路径规则字符串),它直到Git 2.11才一样!
请参阅commit d426430的Emily Xie (emilyxxie
)(2016年6月22日)。
(由Junio C Hamano -- gitster
--在commit 3b1e135合并,2016年10月26日)
pathspec
:警告空字符串作为pathspec作为pathspec元素的空字符串匹配所有路径。 但是,一个错误的脚本可能会意外地将一个空字符串分配给一个变量,然后传递给Git命令调用,例如:
path=... compute a path to be removed in $path ...
git rm -r "$paht"
这会无意中删除当前目录中的所有路径。
解决此问题需要采用两步法。
- 由于可能存在以这种方式故意使用空字符串的现有脚本,第一步只是发出警告:(1)告诉空字符串将成为无效的pathspec元素,(2)要求用户使用“
.
”如果他们的意思是匹配所有。- 对于第二步,稍后的几个发布周期的后续补丁将删除警告并引发错误。
Git 2.15.x / 2.16更新(2018年第一季度):
消息“将在即将发布的版本中失效”消失,并变为:
empty string is not a valid pathspec.
please use . instead if you meant to match all paths
请参阅commit 9e4e8a6撰写的Emily Xie (emilyxxie
)(2017年6月7日)。
请参阅commit 229a95a撰写的Junio C Hamano (gitster
)(2017年6月23日)。
(2017年11月6日在Junio C Hamano -- gitster
--由commit 728c573合并)
作为pathspec元素的空字符串匹配所有路径。 但是,一个错误的脚本可能会意外地将一个空字符串分配给一个变量,然后传递给Git命令调用,例如:
path=... compute a path to be removed in $path ...
git rm -r "$path"
这会无意中删除当前目录中的所有路径。