Quite an old question, but since I was struggling with this issue even now, I figured I would share the actual solution to the problem.
The thing is, while you cannot commit empty directories in Git as if they were ignored, this rule does not apply to .gitignore
.
From https://git-scm.com/docs/gitignore
A trailing "/*" matches everything inside. For example, "abc/*"
matches all files inside directory "abc", relative to the location of
the .gitignore file, with infinite depth.
A slash followed by two consecutive asterisks then a slash matches
zero or more directories. For example, "a/**/b" matches "a/b",
"a/x/b", "a/x/y/b" and so on.
** Matches everything inside - literally everything - files AND directories.
This leads us to another point in gitignore docs:
An optional prefix "!" which negates the pattern; any matching file
excluded by a previous pattern will become included again. It is not
possible to re-include a file if a parent directory of that file is
excluded. Git doesn’t list excluded directories for performance
reasons, so any patterns on contained files have no effect, no matter
where they are defined. Put a backslash ("") in front of the first
"!" for patterns that begin with a literal "!", for example,
"!important!.txt".
If the pattern ends with a slash, it is removed for the purpose of the
following description, but it would only find a match with a
directory. In other words, foo/ will match a directory foo and paths
underneath it, but will not match a regular file or a symbolic link
foo (this is consistent with the way how pathspec works in general in
Git).
Now, let's say we have a following dir structure:
/path/to/git/repo
|-- .gitignore
|-- /cache
|-- somefile
|-- README
|-- /dir
|-- somefile2
|-- README
And we want to ignore all files inside cache/ except for README files.
If we specify gitignore like this:
/cache/**
!README
Git will ignore everything except for /cache/README
. The other README won't show up because its directory /cache/dir
was excluded with /cache/**
and !README
won't even apply to it.
To solve the issue we need to specify gitignore as this:
# Ignore everything inside cache/ dir
/cache/**
# Except for subdirectories(won't be commited anyway if there is no commited file inside)
!/cache/**/
# And except for README files
!README