Escaping characters in glob patterns in Git
Yes, the escape character suppresses the file name expansion normally performed by the Unix shell. To answer the subquestions:
git rm
implements its own expansion likely because the files might not be present in the checked-out directory. (Think of the situation where you firstrm *~
, and then remember that you also want to remove them fromgit
.)Using the backslash escape character (or wrapping the argument in quotes) does exactly that — suppresses file name expansion at the shell level. This cannot be done by
git
automatically becausegit
doesn't control your shell, by the time it is executed, the expansion is already over. The expansion must be prevented by the shell itself or, more realistically, by the end user invokinggit
through the shell.
Why does git use its own filename expansion?
@user4815162342's answer is missing a key reason to escape a glob metacharacter (e.g., *
) from the shell:
git's filename expansion is recursive. Your shell's filename expansion is not. To confirm:
mkdir testA testA/testB
cd testA
touch test1.txt testB/test2.txt
git init
Now you have a directory structure and git repo to use to test recursive filename expansion. While in testA:
echo *.txt
# test1.txt
git add \*.txt
git status
# On branch master
#
# No commits yest
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: test1.txt
# new file: testB/test2.txt
You can see that filename expansion by the shell is not recursive, as echo *.txt
only expanded to text file in the testA
directory. If you had run git add *.txt
, you would have only added test1.txt
. On the other hand, filename expansion in git is recursive. When you run git add \*.txt
, suppressing the glob metacharacter from the shell and allowing git to expand it, it expands to all .txt
files in your repo, which includes subdirectories.