Search code examples
gitgitignore

.gitignore track only one file in a directory at any depth


I am trying to ignore all but a single file in a named directory that could be at any depth. So in a structure like this, I want to track any occurrence of build/.gitkeep but ignore all other files in and below build/. The items to track are marked with ++. The items to ignore are marked with --.

    |.gitignore                               ++
    |Makefile                                 ++
    |--build/                                 ++
    |--build/.gitkeep                         ++
    |--build/ignore_any_file                  --
    |--build/ignore_any/dir                   --
    |--foo/                                   ++
    |--foo/file_to_keep                       ++
    |--foo/dir_to_keep/                       ++
    |--foo/dir_to_keep/stuff                  ++
    |--foo/build/                             ++
    |--foo/build/.gitkeep                     ++
    |--foo/build/ignore_any_file              --
    |--foo/build/ignore_any/dir               --
    |--foo/build/ignore_any/dir/subir         --
    |--bar                                    ++
    |--bar/file_to_keep                       ++
    |--bar/dir_to_keep/                       ++
    |--bar/dir_to_keep/stuff                  ++
    |--bar/build/                             ++
    |--bar/build/.gitkeep                     ++
    |--bar/ignore_any_file                    --
    |--bar/ignore_any/dir                     --
    |--bar/ignore_any/dir/subir               --
    |--foobar/foo                             ++
    |--foobar/foo/file_to_keep                ++
    |--foobar/foo/dir_to_keep/                ++
    |--foobar/foo/dir_to_keep/stuff           ++
    |--foobar/foo/build/                      ++
    |--foobar/foo/build/.gitkeep              ++
    |--foobar/foo/build/ignore_any_file       --
    |--foobar/foo/build/ignore_any/dir        --
    |--foobar/foo/build/ignore_any/dir/subir  --

I have tried many, many combinations. The sticking point for me seems to be having build/ at any depth. I am trying to avoid have to create entries for every path where build/ exists. I also don't want to create .gitignore files in every instance of build/.

    $ git --version
    git version 2.20.1

Solution

  • You should make sure to exlude folders from your ignore rule, if you want then to be able to exclude a file:

    build/**
    !build/**/
    !build/**/.gitkeep
    

    This is because:

    It is not possible to re-include a file if a parent directory of that file is excluded

    In your case (build at any depth)

    **
    !**/
    !build/.gitkeep
    !**/build/.gitkeep
    

    The OP nelsonov made it work (in the comments) with:

    build/** 
    !build/**/ 
    !build/ 
    !build/.gitkeep 
    !**/build/ 
    !**/build/.gitkeep 
    **/build/**