guide

Why Is It Ignored? Debugging with git check-ignore

How to find which rule ignores a file with git check-ignore -v, git status --ignored and git ls-files, and a checklist of 7 common reasons a rule does not work.

As rules pile up, questions arise: "Why can't I see this file?" or "Why does it keep showing up?" git has commands that answer them.

git check-ignore -v

git check-ignore -v logs/app.log src/build/keep.txt

The output format is source:line:pattern<TAB>path.

.gitignore:3:*.log	logs/app.log

To also see paths that did not match, add --non-matching (-n).

Use --no-index for tracked files

Ignore rules do not apply to files that are already tracked, so by default check-ignore prints nothing for them either. If you only want to know whether a rule matches the file, add --no-index.

$ git check-ignore -v app.log            # tracked, so no output
$ git check-ignore -v --no-index app.log
.gitignore:3:*.log	app.log

Listing ignored files

# Show ignored entries along with status (marked !!)
git status --ignored --short

# List every ignored file individually
git ls-files --others --ignored --exclude-standard

# Tracked files that match ignore rules
git ls-files -ci --exclude-standard

When an entire directory is ignored, git status --ignored shows it as a single directory, as in !! logs/. To see individual files, use ls-files.

Common reasons a rule does not work

  1. It is already tracked. This is the most common. If git ls-files <path> prints something, the file is tracked. Stop tracking it with git rm --cached.
  2. A parent directory is excluded. With dir/ ignored, !dir/file has no effect. Change it to dir/*.
  3. The order is reversed. If a broader rule appears again after a negation rule, the broader rule wins. The line number from check-ignore -v shows this right away.
  4. Trailing whitespace. The space at the end of *.log is stripped, but spaces before the pattern and invisible characters such as full-width spaces remain part of the pattern.
  5. Slash direction. gitignore uses only / as the path separator, even on Windows. In build\output the backslash is interpreted as an escape, so it does not work as intended.
  6. Misunderstanding anchoring. config/local.json matches only config at the root because of the slash in the middle. To apply it at any depth, use **/config/local.json.
  7. Case. In environments where core.ignorecase is false (usually Linux), *.JPG and *.jpg are different. Repositories created on macOS or Windows are usually true, which can lead to rules that work locally but not in CI.

Checking in the browser first

If you want to try out rule changes and compare results before applying them to the repository, this site's Pattern test tab is convenient. Paste your rules and a list of paths, and it shows for each path the result, the deciding rule (with line number), and whether it was ignored because of a parent directory. You can use the output of git ls-files or find . -type f as-is for the path list. However, confirm the final verdict, which combines .gitignore files in subdirectories and global settings, with git check-ignore -v in the repository.

References

← PreviousIgnoring Files That Are Already Committed