Categories
git gitignore

Make .gitignore ignore everything except a few files

2321

I understand that a .gitignore file cloaks specified files from Git’s version control.

How do I tell .gitignore to ignore everything except the files I’m tracking with Git? Something like:

# Ignore everything:
*

# Do not ignore these files:
script.pl
template.latex

1

3175

An optional prefix ! which negates the pattern; any matching file excluded by
a previous pattern will become included again. If a negated pattern matches,
this will override lower precedence patterns sources.

# Ignore everything
*

# But not these files...
!.gitignore
!script.pl
!template.latex
# etc...

# ...even if they are in subdirectories
!*/

# if the files to be tracked are in subdirectories
!*/a/b/file1.txt
!*/a/b/c/*

17

  • 22

    It looks like this also ‘ignores’ subfolders, such that any files named ‘script.pl’ in anything other than the root dir won’t be found anyway. I’m using this now (with *.pl) and all *.pl files are being ignored even though there are many in the subdirectories below the .gitignore file

    – PandaWood

    Nov 6, 2011 at 1:44


  • 49

    @PandaWood That issue was brought up here (stackoverflow.com). It’s caused by the first expression matching everything including directories, which you never negate. To fix, add (!*/), which matches any subdirectories (recursively) in current directory. This won’t help the parent answer, which is whitelisting specific files (if they’re in subdirectories, you’d probably want to manually specify the full path, or use directory-specific .gitignore files).

    – simont

    Feb 10, 2012 at 12:51


  • 51

    I couldn’t get this to work. I am ignoring a folder (e.g. wp/) but I want to NOT ignore some files deep in that folder (e.g. wp/path/to/some/location/*). The only way I could get it to work was by doing git add -f wp/path/to/some/location/*

    – trusktr

    Apr 16, 2012 at 23:36


  • 15

    @trusktr Use simont’s !*/ exception

    Oct 9, 2012 at 6:41

  • 8

    Geez that last rule: !*/ makes all the difference in my futile attempts to wrangle a .gitignore file to work. Thank you very much.

    – racl101

    Jan 22, 2015 at 23:00

875

If you want to ignore the whole content of a directory except one file inside it, you could write a pair of rules for each directory in the file path. E.g. .gitignore to ignore the pippo folder except from pippo/pluto/paperino.xml

pippo/*
!pippo/pluto
pippo/pluto/*
!pippo/pluto/paperino.xml

Note that if you simply had written above:

pippo/*
!pippo/pluto/paperino.xml

It wouldn’t work because the intermediary pluto folder would not exist to Git, so paperino.xml could not find a place in which to exist.

11

  • 93

    Excellent answer, but It’s worth noting for anyone coming across this later that foo and foo/* are not the same. For this to work, you need to use foo/* for the base folder

    Jul 30, 2016 at 16:13


  • 36

    @Mayank Pippo is Goofy in italian while Paperino is Donald Duck and Pluto is the same as in english. They used to be a very common triplet of variable names for programming samples back in the days. It was nice to read them again.. 🙂

    – Ghidello

    Feb 1, 2017 at 20:47


  • 10

    doesn’t work for me: node_modules/* !node_modules/bootstrap

    Sep 13, 2017 at 7:40

  • 2

    you must include !.gitignore or else this wont work. .gitignore file will also untracked by git

    – suhailvs

    Jul 14, 2018 at 2:38

  • 2

    @simple_human That would be true if he was ignoring everything in repository root, or if he had .gitignore file to care about, inside mentioned directories.

    – xZero

    Dec 14, 2018 at 13:58


333

You want to use /* instead of * or */ in most cases

Using * is valid, but it works recursively. It won’t look into directories from then on out. People recommend using !*/ to includelist directories again, but it’s actually better to blocklist the highest level folder with /*

# Blocklist files/folders in same directory as the .gitignore file
/*

# Includelist some files
!.gitignore
!README.md

# Ignore all files named .DS_Store or ending with .log
**/.DS_Store
**.log

# Includelist folder/a/b1/ and folder/a/b2/
# trailing "/" is optional for folders, may match file though.
# "/" is NOT optional when followed by a *
!folder/
folder/*
!folder/a/
folder/a/*
!folder/a/b1/
!folder/a/b2/
!folder/a/file.txt

# Adding to the above, this also works...
!/folder/a/deeply
/folder/a/deeply/*
!/folder/a/deeply/nested
/folder/a/deeply/nested/*
!/folder/a/deeply/nested/subfolder

The above code would ignore all files except for .gitignore, README.md, folder/a/file.txt, folder/a/b1/ and folder/a/b2/ and everything contained in those last two folders. (And .DS_Store and *.log files would be ignored in those folders.)

Obviously I could do e.g. !/folder or !/.gitignore too.

More info: http://git-scm.com/docs/gitignore

11

  • 5

    Very clever, thanks. IMO, this is the best way to go about it for WordPress sites with the minimum number of inclusion rules. Also, any new plugins, themes or WP updates aren’t removed or added without your express permission. When using GitHub Desktop I find .DS_Store files are not ignored, but via command line this is not an issue. To get around this I had to move the **/.DS_Store below all other rules.

    – Jibran

    May 18, 2016 at 0:32

  • 10

    My inner syntax highlighter is having a strange reaction to the title of your post.

    – itsadok

    Jun 10, 2016 at 7:49

  • 3

    Gracias! you can also whitelist a file in a folder.. !/some/folder/file.txt

    Jun 27, 2017 at 14:47

  • 2

    @dallin there is no difference. One whitelists a folder and the other whitelists the children of that folder, which does the same thing. The only problem is a folder or files’s parent has to be whitelisted before it can be whitelisted, so you can’t do /* then !/nested/folder/* (or the equivalent !/nested/folder) without doing !/nested/ or !/nested first! (and probably /nested/* in between). A trick to remember is if you’re whitelisting a deeply nested subfolder you need to black the children in each subfolder all the way up, and those blacklists will end with the “slash star”…

    Feb 6, 2019 at 19:59


  • 1

    Why there’s backslash with **/.DS_Store but not with **.log?

    – FritzDC

    Aug 19, 2020 at 14:13