The rule is simple:
It is not possible to re-include a file if a parent directory of that file is excluded.
That is why you need to
-
ignore files and folders recursively:
/foo/**
(if you only ignore /foo/
, that is the folder, then no amount of ‘!
‘ exclusion rule will work, since the foo/
folder itself is ignored: Git will stop there)
-
Then exclude folders from the ignore rules:
!/foo/**/
-
Before whitelisting files like the
.gitkeep
!/foo/**/.gitkeep
That works because the .gitkeep
parent folders are excluded from the ignore rules.
As opposed to Bernardo original proposal (before his edit):
/foo/**
!**/.gitkeep
If does not exclude folders from the /**
ignore rule, so the exclusion rule for files is inoperative.
You can check that with:
git check-ignore -v -- /path/to/.gitkeep
As mentioned in scm .gitignore
:
- using ‘
*
‘ is the same as ‘**
‘ - using
!.gitkeep
(without any / anchor) would exclude that file recursively.
In both cases, ‘recursively
‘ is the key term which explains why exclusion rules can apply: if you ignore a folder (like .
or /foo/
), you won’t be able to exclude anything inside that folder.
But if you ignore elements (files and folder) recursively (*
or **
), and exclude folders from gitignore rules (again through recursive rule !*
), then you can exclude (white-list) files.