.gitignore: what git should not notice

Updated July 31, 2026

.gitignore is a file listing everything git must ignore: temporary files, dependency directories, build artifacts, local secrets.

It usually sits in the root of the repository and is committed along with the code, so that git stays quiet about the same things for everyone who clones the project. One rule per line.

$ cat .gitignore
# dependencies and build output
node_modules/
build/

# logs and local stuff
*.log
.env
.DS_Store

node_modules/ is the whole directory; the trailing slash says the rule is about a directory. *.log is a pattern: the asterisk stands for any run of characters inside a name. .env is an exact name. A # at the start of a line is a comment. A rule with no slash in it at all applies at any depth. As soon as a slash shows up (/build, docs/tmp), the path is counted from the directory that holds the .gitignore itself, and a nested a/docs/tmp no longer matches. A line starting with ! brings a file back: *.log hides every log, and adding !logs/keep.log below it keeps one of them visible.

Which rule hid a file is a question for git check-ignore:

$ git check-ignore -v build/app.js
.gitignore:3:build/	build/app.js

A .gitignore can also live in a subdirectory: its rules apply from that directory down.

A file that is already tracked

This is where everyone trips. .gitignore only works on things git is not watching yet. If config.env made it into a commit once, a new rule changes nothing: the file is tracked, and git keeps reporting its changes. You have to take it out from under git's watch first, leaving it on disk:

$ git rm --cached config.env
rm 'config.env'
$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	deleted:    config.env

The --cached flag is the important part: without it git rm would delete the file from disk too. After the commit the rule starts working, and the file stops showing up in git status.

Common mistakes

Negation does not work if a whole directory is excluded: with the rule logs/, a line !logs/keep.log gives you nothing, because git never looks inside a hidden directory. Write logs/* instead and the exception takes effect. Second: git add debug.log on an ignored file refuses and suggests the -f flag, so think about whether you really want it. And the big one: .gitignore does not remove a secret that already made it into the history. Treat a key that was ever in a commit as compromised and reissue it.

Where this is in the book

The full treatment is in Chapter 4. Inspect, undo, ignore. Next to it, git status is worth a look.

To practise it by hand, take the interactive lesson Undoing changes.