133

I am attempting to use a .gitignore file with negated patterns (lines starting with !), but it's not working the way I expect.

As a minimal example, I have the folllowing directory structure:

C:/gittest
 -- .gitignore
 -- aaa/
   -- bbb/
     -- file.txt
   -- ccc/
     -- otherfile.txt

and in my gitignore file, I have this:

aaa/
!aaa/ccc/

My understanding (based on this doc page) is that the file aaa/ccc/otherfile.txt should not be ignored, but in fact git is ignoring everything under aaa.

Am I misunderstanding this sentence: "An optional prefix ! which negates the pattern; any matching file excluded by a previous pattern will become included again."?

BTW, this is on Windows with msysgit 1.7.0.2.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Chris Perkins
  • 3,350
  • 4
  • 21
  • 16

3 Answers3

223

I think that what you actually want to do is:

aaa/*
!aaa/ccc

You're telling it "don't look in aaa" so it never even examines the path aaa/ccc. If you use the wildcard, it still reads the contents of aaa, then each entry matches the wildcard and is ignored, except aaa/ccc which gets put back in.

Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • 2
    @iconoclast: Then you're probably doing something different. Post another question (with complete information) if you want help. – Cascabel Aug 16 '12 at 04:13
  • This didn't work for me either: /apps/* !/apps/myApps/FluidTest/bin/ – sleep Mar 27 '13 at 07:49
  • 7
    @Jarrod It does work; you're just doing something different. You'll have to use this method recursively, for exactly the reasons given in the answer. !apps/myApps, apps/myApps/* and so on. – Cascabel Mar 27 '13 at 13:46
  • Wonder why it doesn't work for aaa/**/* !aaa/ccc/eee (ignore everything, except files at certain path) – Phương Nguyễn Mar 13 '14 at 02:50
  • Same concept apply for subdirectories : ignore aaa/**/*, so never read content of aaa/ccc/*, so never matches !aaa/ccc/eee -- the same for !/apps/myApps/FluidTest/bin/ . To ignore everything but a specific subfolder you have to reignore and unignore all level of the tree this way : (aaa/* !aaa/ccc aaa/ccc/* !aaa/ccc/eee) (/apps/* !/apps/myApps /apps/myApps/* !/apps/myApps/FluidTest /apps/myApps/FluidTest/* !/apps/myApps/FluidTest/bin). **[See examples in action](https://gitlab.com/celinederoland/draft-gitignore-negated-patterns)** – Céline de Roland Feb 02 '22 at 06:38
28

If you want to exclude everything in aaa, but include aaa/ccc and everything beneath it, you should use:

aaa/*
!aaa/ccc
!aaa/ccc/*

The first line tells git to ignore everthing beneath aaa, the second tells it not to ignore the folder aaa/ccc which actually "enables" the third line which then tells it not to ignore everything beneath aaa/ccc.

xmak
  • 1,060
  • 9
  • 8
6

If anyone's still not seeing newly un-ignored items in a git status running a git update-index before hand can help git to see the changes (at least in version 1.9.x of gitbash).

alexkb
  • 3,216
  • 2
  • 30
  • 30