4

I'm encountering a problem where git check-ignore is not respecting .gitignore's 'not' (!) rules. It's returning "Ignored" if a file matches any entry in the .gitignore file, regardless of whether that entry is telling it to not ignore the path (via the ! operator)

git check-ignore's documentation states the return codes map as follows:

EXIT STATUS

  • 0: One or more of the provided paths is ignored.
  • 1: None of the provided paths are ignored.
  • 128: A fatal error was encountered.

This doesn't match what I'm seeing when I add "Do not ignore" rules, i.e. sticking ! in front of an entry.

As an example, let's create a file structure as follows:

.gitignore
files/
    path-not-ignored
ignored-files/
    path-ignored
    path-not-ignored

and a .gitignore containing:

ignored-files/*
!ignored-files/path-not-ignored

According to the documentation, I'd expect the files in files/ and ignored-files/path-not-ignored to return exit status 1 (not ignored), and ignored-files/path-is-ignored to return 0 (ignored).

What I'm seeing instead of everything in ignored-files returning exit status 0 (ignored):

File                             | Expected exit status | Actual exit status | Summary
-------------------------------- | -------------------- | ------------------ | -------
`files/path-not-ignored`         | 1 (Not ignored)      | 1 (Not ignored)    | Expected
`ignored-files/path-ignored`     | 0 (Ignored)          | 0 (Ignored)        | Expected
`ignored-files/path-not-ignored` | 1 (Not ignored)      | 0 (Ignored)        | Unexpected

(Exit status codes are being checked with git check-ignore <file>;echo $?)

This doesn't match Git's internal behaviour, because I can git add add ignored-files/path-not-ignored just fine:

File                             | `git add`?                   | Matches `git check-ignore` output?
-------------------------------- | ---------------------------- | ----------------------------------
`files/path-not-ignored`         | Adds file (as expected)      | Yes
`ignored-files/path-ignored`     | Throws warning (as expected) | Yes
`ignored-files/path-not-ignored` | Adds file (as expected)      | No


git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   files/path-not-ignored
    new file:   ignored-files/path-not-ignored

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    .gitignore

As git check-ignore is unreliable in this case, are there any other commands I could use to check whether Git is ignoring / not ignoring a given file?

Something that returns exit codes would be ideal, as I'm using this in a bash script.

Rob Jackson
  • 138
  • 7
  • One option might be to use `git add --dry-run`. It's unfortunate that Git has this bug though... it looks like there's code that should be handling the negation, but I bet it's not working correctly with the globbing. – John Szakmeister Jul 20 '17 at 09:42
  • Hmmm... looking at the man page, I'm not sure that it's behaving badly given the subject ("Debug gitignore / exclude files"). OTOH, given the documented return values I'd say it is behaving badly. I'll enquire on the git list about this. – John Szakmeister Jul 20 '17 at 10:22
  • It looks like this is an issue, though the -q option may be needed to invoke the exit status. The -v -n options can help debug if the ignore order matters, and multiple paths can be given to split out the cases. – Philip Oakley Jul 23 '17 at 18:09
  • The tests of git-check-ignore that are in the git repo are all in [\git\t\t0008-ignores.sh](https://github.com/git/git/blob/master/t/t0008-ignores.sh) (all 845 lines) – Philip Oakley Jul 23 '17 at 19:44
  • Junio responded saying that he believes check-ignore started out as a [debugging aid](http://marc.info/?l=git&m=150092424004428&w=2) (rather than a way to check if a file is ignored). So using it this way is not its original intent. If you're willing to parse the output of a `git status` call, you could consider using `git status --ignored --porcelain ` and looking for `!!` at the beginning of the line. Not sure how that would work with directories. – John Szakmeister Jul 27 '17 at 11:17
  • See also https://stackoverflow.com/questions/12144633/which-gitignore-rule-is-ignoring-my-file (2012 - 2016) and https://stackoverflow.com/questions/466764/git-command-to-show-which-specific-files-are-ignored-by-gitignore (2009 - 2012). The (2017) git mailing list discussion is at https://stackoverflow.com/questions/466764/git-command-to-show-which-specific-files-are-ignored-by-gitignore. Sounds like it's an 'open' problem for someone. – Philip Oakley Jul 30 '17 at 16:15

1 Answers1

1

Check if the issue persists since July 2017 with Git 2.18 (July 2018).

Commit d60771e might have helped remove false positive.

check-ignore: fix mix of directories and other file types

In check_ignore(), the first pathspec item determines the dtype for any subsequent ones.
That means that a pathspec matching a regular file can prevent following pathspecs from matching directories, which makes no sense.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250