I have the following folder structure:
/foo/
/foo/test.txt
/foo/.gitkeep
/foo/bar/test.txt
/foo/bar/.gitkeep
/foo/bar/baz/test.txt
/foo/bar/baz/.gitkeep
Now I want to exclude all files in the folder "foo" and all files in its subfolders (and subsubfolders), except all the .gitkeeps (so that the folder structure is kept). This should also work for more than 3 levels of subfolders.
The following gitignore-rules work:
/foo/**
!/foo/**/
!/foo/**/.gitkeep
Can somebody explain, why this works? Is there a cleaner way of doing this?
gitignore file is usually placed in the repository's root directory. However, you can create multiple . gitignore files in different subdirectories in your repository.
A . gitignore file is a plain text file where each line contains a pattern for files/directories to ignore. Generally, this is placed in the root folder of the repository, and that's what I recommend. However, you can put it in any folder in the repository and you can also have multiple .
If you want to ignore a file that you've committed in the past, you'll need to delete the file from your repository and then add a . gitignore rule for it. Using the --cached option with git rm means that the file will be deleted from your repository, but will remain in your working directory as an ignored file.
gitignore file does not exclude the directories unless I fully qualify the ignore pattern as Solution/Project/bin/Debug - which I don't want to do as I will need to include this full pattern for each project in my solution, as well as add it for any new projects added. Any suggestions?
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
:
*
' is the same as '**
'!.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.
I've done it. It seems that what is needed is a .gitignore
file inside the desired folder.
Look at this repository, which does exactly what you want.
I've tried to add any filename inside foo/
, foo/bar/
and foo/bar/baz/
but it only accepts .gitkeep.
The trick is to create a .gitignore with this content, inside the folder:
*
!*/
!.gitignore
!.gitkeep
[Edit: Added based on comments]
And you should be able to shorten this to:
*
!*/
!.git*
Though it may be less clear in the future what was intended.
While this solution doesn't shorten the number of lines required from your original .gitignore
, this does have several other advantages - the main one being that this will be a .gitignore
file inside the folder, which means it can be a clean file that has just these lines, and is specific to just this folder.
That means this .gitignore
file can be easily moved into any specific folder that requires this filter. Also, the entire folder can be easily moved around within the repo, or even moved to a different repo, without needing to modify the .gitignore
. It is much cleaner and more maintainable, and not buried in the typically large .gitignore
file in the repo's root folder.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With