Git gitignore

A .gitignore file tells Git which untracked files and directories to leave alone, keeping build output, secrets, and local machine noise out of your repository.

What .gitignore Controls

Git only ever tracks files you've explicitly added at some point. .gitignore doesn't stop you from tracking a file that's already tracked, it only affects untracked files, telling commands like git status and git add . to skip anything matching its patterns. It's plain text, one pattern per line, and typically lives at your repository root, though additional .gitignore files in subdirectories can add folder-specific rules.

Pattern Syntax and Wildcards

Patterns are matched like shell globs. A single * matches any characters except a slash, so *.log matches error.log at any depth. Two asterisks, **, match across directory boundaries, so logs/**/debug.log matches both logs/debug.log and logs/2026/07/debug.log. A trailing slash restricts a pattern to directories only, and a leading slash anchors it to the location of the .gitignore file itself rather than matching everywhere in the repo.

A starter .gitignore for a Node project

node_modules/
dist/
.env
*.log
.DS_Store
PatternMatches
*.logAny .log file at any depth
/buildbuild/ only at the repo root, not src/build
logs/Any directory named logs, anywhere
**/tempAny file or directory named temp, at any depth
debug.logdebug.log anywhere in the repository

Negation: Un-Ignoring a File

A pattern prefixed with ! re-includes a file that would otherwise be excluded by an earlier rule. This is commonly used to ignore a whole directory of build artifacts while still tracking one important file inside it, such as a .gitkeep placeholder. Order matters: you generally cannot re-include a file inside a directory that was itself excluded by a directory-level pattern, only files excluded by a file-level wildcard.

Ignore everything in a folder except one file

config/*
!config/defaults.yml

Debugging Ignore Rules

It's easy to write a pattern that doesn't do what you expect. Two commands make this easy to debug: git status --ignored lists every file currently being ignored, and git check-ignore -v reports exactly which line, in which file, is responsible for ignoring a given path.

See what's being ignored

$ git status --ignored

Trace which rule ignores a file

$ git check-ignore -v src/config/local.json

Untracking Files Already Committed

Adding a pattern to .gitignore has no effect on files Git is already tracking, a common source of confusion when someone commits a .env file before it was ignored. To fix that, untrack the file explicitly while leaving it on disk, then commit the removal.

Stop tracking a file without deleting it

$ git rm --cached .env
$ git commit -m "Stop tracking .env, now gitignored"
  • node_modules/, vendor/ - installed dependencies, always regenerable
  • dist/, build/, out/ - compiled or bundled output
  • .env, *.local - machine-specific config and secrets
  • *.log, npm-debug.log* - runtime and tool logs
  • .DS_Store, Thumbs.db - OS-generated clutter files
  • .idea/, .vscode/ - editor settings, team preference, some teams track .vscode/settings.json deliberately
Note: Use GitHub's github/gitignore repository as a starting point. It maintains curated templates per language and framework, so you rarely need to write one from scratch.
Note: Ignoring a file does not remove its history. If a secret was committed before you added it to .gitignore, it's still sitting in every earlier commit; rotate the credential and consider a tool like git filter-repo to purge it from history.

Exercise: Git .gitignore

What is the purpose of a .gitignore file?