Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.gitignore directory/wildcard unexpected behaviour

Folder structure of the git project:

.git/
    <some git stuff>
.gitignore
level1/
    level2/
        file1
        file2

The files .gitignore, file1, and file2 are all empty. I run git add .gitignore and git commit -m "create empty .gitignore".

If the .gitignore is emtpy, git add -A followed by git status outputs (as expected):

new file: level1/level2/file1
new file: level1/level2/file2

So, I git reset to begin testing the outcome of changes to the .gitignore (assume I do this between each of the following changes to the .gitignore)

If the .gitignore contains either level1, level1/, level1/*, level2, or level2/, then git add -A followed by git status outputs (as expected):

modified: .gitignore

However, if the .gitignore contains level2/*, then git add -A followed by git status outputs:

modified: .gitignore
new file: level1/level2/file1
new file: level1/level2/file2

Why doesn't level2/* have the same effect as level2/ in this case? Also, while level2/* doesn't do what I want, **/level2/* does.

like image 330
Captain_Obvious Avatar asked Oct 24 '25 18:10

Captain_Obvious


1 Answers

As per the gitignore documentation:

1) If the pattern ends with a slash, it would only find a match with a directory.

2) If the pattern does not contain a slash /, Git treats it as a shell glob pattern and checks for a match against the pathname relative to the location of the .gitignore file (relative to the toplevel of the work tree if not from a .gitignore file).

3) Otherwise, Git treats the pattern as a shell glob suitable for consumption by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will not match a / in the pathname. For example, "Documentation/*.html" matches "Documentation/git.html" but not "Documentation/ppc/ppc.html" or "tools/perf/Documentation/perf.html".

The pattern level2/* falls into the third case. Since there is no directory level2 at the root of the project, git doesn't ignore the files in level1/level2/.

That's why **/level2/* does work, and also why level2/ and level2 work.

like image 110
Captain_Obvious Avatar answered Oct 26 '25 08:10

Captain_Obvious