Search code examples
gitgitignore

Git, set up .gitignore to ignore all files EXCEPT .conf files, including subdirectories too


How to get Git to ignore all files in a directory and ALSO in its subdirectories except for .conf files?

Currently I have this in my .gitignore:

!/some/dir/
/some/dir/*
!/some/dir/**/
!/some/dir/**/*.conf

So, I want to ignore all files in /some/dir/ and also its subdirectories, except for *.conf files.

But it is not ignoring any file in /some/dir/.

For example, /some/dir/somefile is not ignore, /some/dir/subdir/anotherfile is not ignore also. I just want to not ignore files like: /some/dir/subdir/file.conf.


Solution

  • You may wish to tweak this in various ways, but here's the simplest thing I know of that meets your stated requirements. Create a .gitignore file inside some/dir that reads:

    *
    !*/
    !*.conf
    

    and you're all set.

    Here is an example:

    $ mkdir test-ignore
    $ cd test-ignore
    $ git init
    Initialized empty Git repository in ...
    $ echo test ignore rules > README
    $ git add README 
    $ git commit -m initial
    [master (root-commit) 33962fc] initial
     1 file changed, 1 insertion(+)
     create mode 100644 README
    $ mkdir -p some/dir/a some/dir/b
    $ touch some/dir/file some/dir/a/a.conf some/dir/b/b.conf some/dir/a/ignored
    $ cat > some/dir/.gitignore << END
    > *
    > !*/
    > !*.conf
    > END
    $ git add .
    $ git status
    On branch master
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
            new file:   some/dir/a/a.conf
            new file:   some/dir/b/b.conf
    
    $ 
    

    Explanation

    • * means ignore everything (that is currently untracked, of course; tracked files cannot be ignored).
    • !*/ means if it's a directory, don't ignore it, do search it, and being later in the file, this overrides a previous entry; of course, being searched does not make files in the directory get added, but the subdirectory does get scanned;
    • !*.conf means if a file's base name matches *.conf, don't ignore it, so any files in some/dir named that are named *.conf, or any files in any subdirectory of some/dir that are named *.conf, are not-ignored and hence get added.

    That's why some/dir/a/a.conf did get added, but some/dir/a/ignored did not.

    (You didn't specify in text what you want to do with some/dir/somefile and some/dir/thing.conf so I had the same rules apply here: file is ignored and thing.conf is not-ignored. I think that's what you intended with !**/*.conf.)

    In general, moving a .gitignore file "down the tree" as far as it goes will simplify it, so it's easier to put this in some/dir/.gitignore. The general rule !*/, close enough to the end of a .gitignore, forces Git not to short-circuit the scanning of subdirectories found recursively. Other than these two rules (which should be obvious, but aren't always obvious at first), the rest is obvious.