Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Escaping characters in glob patterns in Git

Tags:

git

shell

The following git command (which deletes all files that end in a ~) uses escape characters

git rm \*~

The rationale is that git uses it's own filename expansion in addition to the expansion used by the shell.

Does this mean the escape characters are a way to suppress the filename expansion done by the shell ?

Somehow I am not able to get a proper handle on this.

  • Why does git use it's own filename expansion ? Is it because shell filename expansion could work in different ways in different shells/OS's
  • If so, why not just suppress filename expansion at the shell level for git commands, and allow git to perform it's own semantics with glob patterns
like image 325
Parag Avatar asked Jan 08 '14 10:01

Parag


2 Answers

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.

like image 103
user4815162342 Avatar answered Sep 19 '22 12:09

user4815162342


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.

like image 35
De Novo Avatar answered Sep 17 '22 12:09

De Novo