Search code examples
gitwildcardgitignoresubdirectorynegation

.gitignore wildcard suffix exclusion with negation for subfolder


I have a .gitignore which is like this:

*.png
*.jpg
*.gif
!0/*.png
!0/*.jpg
!0/*.gif

I want to ignore all image files (.png, .jpg, .gif) in all folders but not in the folder /0/. All image files in this folder should not be ignored.

I tried with the above .ignore file but it is not working as image files in /0/ are still ignored. How to write this correctly?


Solution

  • The ignore pattern:

    !0/*.png
    

    means "don't ignore any *.png file that is directly inside a folder named 0". So this would include 0/abc.png, and it would include 1/0/def.png, but it would exclude 0/1/ghi.png.

    If you want to include all *.png below the folder 0, there are two ways to do this.

    You can use the following pattern:

    *.png
    !/0/**/*.png
    

    The ** pattern matches any series of subdirectories, including the root. Starting the pattern with / means that the pattern must match starting with the current directory. So this will include 0/abc.png, 0/subdir/def.png, and 0/subdir/ghi/jkl.png. It will exclude abc.png and 1/abc.png.

    Alternatively, you can create a file .gitignore with

    *.png
    

    And then you can create another file, 0/.gitignore, which contains:

    !*.png
    

    This is a little more obvious, and it has exactly the same effect.

    Demo

    Here is the base *.png rule, it ignores all *.png files:

    $ git init
    Initialized empty Git repository in .../.git/
    $ mkdir -p 0/1
    $ touch img.png 0/img.png 0/1/img.png
    $ cat >.gitignore
    *.png
    $ git add -n .
    add '.gitignore'
    

    Here is the rule you have, which includes any *.png inside any directory named 0:

    $ cat >.gitignore
    *.png
    !0/*.png
    $ git add -n .
    add '.gitignore'
    add '0/img.png'
    

    Here is the fixed pattern:

    $ cat >.gitignore  
    *.png
    !/0/**/*.png
    $ git add -n .
    add '.gitignore'
    add '0/1/img.png'
    add '0/img.png'
    

    Here is the alternative:

    $ cat >.gitignore
    *.png
    $ cat >0/.gitignore
    !*.png
    $ git add -n .
    add '.gitignore'
    add '0/.gitignore'
    add '0/1/img.png'
    add '0/img.png'