I was trying out some sample instructions of git and came across this peculiar case that when we do a git rm *, it doesn\'t delete the .* files in
Note that the right syntax should be git rm -r . ('dot')
More worrying is git rm -r (empty pathspec string) which does the same until Git 2.11!
See commit d426430 (22 Jun 2016) by Emily Xie (emilyxxie).
(Merged by Junio C Hamano -- gitster -- in commit 3b1e135, 26 Oct 2016)
pathspec: warn on empty strings as pathspecAn empty string as a pathspec element matches all paths.
A buggy script, however, could accidentally assign an empty string to a variable that then gets passed to a Git command invocation, e.g.:
path=... compute a path to be removed in $path ...
git rm -r "$paht"
which would unintentionally remove all paths in the current directory.
The fix for this issue requires a two-step approach.
As there may be existing scripts that knowingly use empty strings in this manner, the first step simply gives a warning that (1) tells that an empty string will become an invalid pathspec element and (2) asks the user to use "
." if they mean to match all.For step two, a follow-up patch several release cycles later will remove the warning and throw an error instead.
Update for Git 2.15.x/2.16 (Q1 2018):
The message "will be made invalid in upcoming releases" disappear, and becomes:
empty string is not a valid pathspec.
please use . instead if you meant to match all paths
See commit 9e4e8a6 (07 Jun 2017) by Emily Xie (emilyxxie).
See commit 229a95a (23 Jun 2017) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 728c573, 06 Nov 2017)
An empty string as a pathspec element matches all paths.
A buggy script, however, could accidentally assign an empty string to a variable that then gets passed to a Git command invocation, e.g.:
path=... compute a path to be removed in $path ...
git rm -r "$path"
which would unintentionally remove all paths in the current directory.
The wildcard gets expanded by your shell, and the expansion does not include dot files, by default, in most shells.
So by the time git executes, the first command has become
git rm -r folder testfile3
and the second probably a literal
git rm -r *
which git then expands by itself.
As remarked by Keith, to remove everything in one go, prevent the shell from expanding the wildcard so that git does the expansion the first time already. This can be done with double or single quotes, or with a backslash before the asterisk. I tend to prefer single quotes:
git rm -r '*'
As user1281385 noted in a comment, the shell expands * the first time around.
The reason the second time removes the dot-files is that once there are no files to match, the shell leaves the literal asterisk as an argument (depending on your shell anyway, at least one variant errors out instead) and git then does its own matching.
When you run git rm * you are actually using the shell's globbing rules to pass arguments to git-rm(1). Many shells don't include hidden files (e.g. files with leading dots) by default. In Bash, you can change the globbing rules with dotglob and GLOBIGNORE. For example:
Using the shopt builtin:
# set dotglob
shopt -s dotglob
git rm *
# unset dotglob
shopt -u dotglob
Using the GLOBIGNORE variable (which also sets dotglob):
# Run git within a modified environment that includes GLOBIGNORE.
GLOBIGNORE='.git' git rm *