I am observing a strange behavior while using git-status with pathspecs. I would like your opinion on whether it is the expected behavior, or an undefined behavior in git.
Initial setup
$ mkdir main && cd main
$ git init .
Initialized empty Git repository in d:/temp/main/.git/
$ touch test[1].txt
$ touch test[2].txt
The following ones are understandable
$ # 1. escaped square brackets
$ git status test\[1\].txt --short
?? test[1].txt
$ # 2. escaped square brackets with range
$ git status test\[[1-9]\].txt --short
?? test[1].txt
?? test[2].txt
$ # 3. unmatched range, with what looks like a fallback to literal comparison
$ git status test[1].txt --short
?? test[1].txt
Additional setup for unexpected behavior
$ touch test1.txt
Unexpected behavior
$ # 4. matched range, so no fallback to literal comparison (this one looks OK)
$ git status test[1].txt --short
?? test1.txt
$ # 5. escaped square brackets => I would expect only test[1].txt to be returned
$ git status test\[1\].txt --short
?? test1.txt
?? test[1].txt
$ # 6. escaped square brackets with range => I would expect only test[1].txt
$ # and test[2].txt to be returned
$ git status test\[[1-9]\].txt --short
?? test1.txt
?? test[1].txt
?? test[2].txt
$ # 7. only escaping the last square bracket
$ # result looks similar to the 5th case
$ git status test[1\].txt --short
?? test1.txt
?? test[1].txt
Additional setup for more fun
$ git add test1.txt
$ rm test1.txt
$ touch test2.txt
More unexpected behavior
$ # 8. ???
$ git status test[1].txt --short
AD test1.txt
?? test[1].txt
$ # 9. We lost test1.txt ???
$ git status test[1-2].txt --short
?? test2.txt
$ # Woo... Should this really work?
$ git status test[*.txt --short
AD test1.txt
?? test2.txt
?? test[1].txt
?? test[2].txt
I’m a bit confused there. I’ve read the Git documentation related to pathspec and it’s not that detailed.
Could anyone help me understand the logic behind?
There are a lot of things to discuss here but I will try to focus on: 1. the logic behind this, 2. How it modifies the behavior.
The logic
Most of the path expansion is done by the shell (hence my comment). Some is done by git, when it has what it takes.
Some tests
The setup
I used this program to investigate the issue:
I know, it’s very high-skill programming.
Tests
We can now have a look at what is going on, and see how the shell modifies what git receives:
Point 1, 2, 3, 4: Everything is working fine, running the small program will give you the same.
Point 5, 6, 7: This time it’s handled by Git, behavior is not that surprising (doing both glob and literal comparison)
Point 8, 9, 10: Well, according to what we’ve seen before, it’s no longer surprising. For 9., no bash comparison matches with test1.txt (removed, hence, … removed)
Conclusion
If you want to test the way Git handles pathspec, you should enclose your path in double quotes:
Hope it helped,