My .gitignore file does not seem to be ignoring all the files I want it to.
================== Context ==================
In my git repo, I have several subdirectories, similar to this reduced example:
git base folder > .gitignore > Folder A > Folder B > Subfolder B0 >SubSubfolder B0a > Files > Subfolder B1 > SubSubfolder B1a > Files > File B1b.ft0 > File B1c.ft0 > File B1d.ft1 > File B1e.ft2 > Etc
I want to ignore all files in Subfolder
B1 except (say) file
B1b.ft0 and file
B1e.ft2. I also want to ignore all files in SubSubfolder
.gitignore file (there is only one), I have these lines:
#Ignore: B1/** B1a/ B0a/ #Include !B1/B1b.ft0 !B1/B1e.ft2
However, all of the files in Subfolder
B1 are included. Files in SubSubfolder
B1a are ignored, however files in SubSubfolder
B0a are not.
============== Attempted Solutions ==============
I decided to start by solving the problem of unignored files in Subfolder
B1/ in the
.gitignore file, but this ignored all the files there, including the ones I want to keep.
I also tried
B1/*.*, but these both fail to ignore the other files in folder
Then I tried manually listing all the files I want to ignore/keep in this folder. This worked, but there are a lot of files and they might change. I don’t want to have to use this option.
================== Methods ==================
When testing if each option works, I used
git check-ignore -v <filename> and
git status --ignore. I also used
git rm --cached -r . followed by
git add -A to clear the repo of ignored files. (Subquestion: do I need to commit the
.gitignore before it will take effect?)
================== Summary ==================
I’m getting more and more confused and annoyed by this, can anyone help me? (Do I just need to apply a generous quantity of *’s all over the place for it to automagically start working, as in this question?)
Please also explain why, and how, your solution works while my ones don’t (if you know).
After a significant amount of testing, reading documentation (quite good), and asking other people, I finally found a solution. (And yes it does involve sprinkling a generous quantity of *’s everywhere). I’ll do my best to explain what I think was going on, and how it can be avoided.
Git was not ignoring the files in Subfolder
B1 because it expected
B1 to be in the root directory. Changing the .gitignore entries to
!**/B1/B1e.ft2 fixed the problem.
The key to understanding this problem is to understand some oddities of the .gitignore syntax. Fortunately, there is not much of it to learn, even though some of it is frustratingly arcane – for instance, you may know that gitignore files are read downwards, leading to this behaviour:
My issue was related to another arcane subtlety in the .gitignore syntax: how it parses filepaths. The gitignore directory separator is
/, but depending on its location in a line, or how many of them there are, it behaves in quite different ways:
For entries with only one
|Git ignores every directory named
||Git ignores any folders and files named
||Git ignores any files and folders named
For entries with multiple
/s, the rules are a combination of the above rules. A few examples demonstrate:
|This pattern matches only one item: a subfolder in the same folder as the .gitignore, named
||This pattern also only matches one item, a subsubfolder named
||This pattern is identical to one in the middle example, except it can also ignore a file named
In all the above cases, files and subdirectories within any ignored directory
foo can not be unignored by e.g.
The devious subtlety is that a
/ at the end of a line like
foo/ will cause any directory named
foo to be ignored, no matter of its depth, but putting any character (including wildcards!) after that
/, or putting any other
/ in the same line will mean it matches only relative to the path where the .gitignore is found. So then, how can files inside a subdirectory be unignored?
The fix is to make better use of the wildcards. There are three wildcards in .gitignore syntax:
?– matches 1 or more characters, except
/. Almost only used for filename matching.
*– matches 0 or more characters, except
**– matches 0 or more characters, including
* can be used to ignore all files in a directory, but not subfolders. The following examples will both ignore all files in the subdirectory
foo resides in the same directory as .gitignore.
foo/?This one will not ignore files with 0-character names.
However, note that these will not ignore files in e.g.
** matches directories, it can solve the above problem like so:
**/foo/. Even though there is a non-whitespace character after the
/, this will ignore all directories and subdirectories named
**/ matches all filepaths.
**/foo/?Ignores all named files inside any directory
foo/**/bar.txtIgnores every file named
bar.txtat any depth inside a folder called
foois in the
**/foo/**Ignores everything inside every directory
foo, but does not ignore the directory itself, and therefore I can unignore a select few files inside it!
Yay! My question is answered – almost.
Regarding SubSubfolder B0a:
For the entry in my .gitignore to ignore SubSubfolder
B0a, I actually had something slightly different from what I asked. In my actual project,
B0a is called
.generated_files. I was not entirely sure what git would think of a .gitignore entry starting with a dot, so I had prefixed it with a slash, like so:
/.generated_files/. (I forgot about this when I wrote the question.) As I have now learnt, this caused git to expect it only in the root directory, and therefore miss it.
I also learnt that git does not care in the slightest if an entry begins with a
Although It was not causing a problem in my case, I also discovered that an entry in a .gitignore file will match both files and folders. So if you had a file named foo and a folder named foo, putting
foo in the .gitignore would cause them both to be ignored.
Hopefully this answer was helpful, I’m afraid it is so long that reading the official documentation might actually be easier to understand.
Answered By – Infinite_Maelstrom