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:

  1. 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 first rm *~, and then remember that you also want to remove them from git.)

  2. 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 because git 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 invoking git 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.

Tags:

Shell

Git