GitIgnoring Files (.gitignore)

Ignoring Files (.gitignore)

Not every file in your project should be in version control. Build outputs, log files, editor settings, secrets, and dependency folders are noise at best and dangerous at worst. Git solves this with a plain text file called .gitignore — list a path or pattern in it and Git stops bothering you about those files.

What to ignore
  • Generated files — build output (dist/, build/, target/), bundles, compiled binaries.

  • Dependency foldersnode_modules/, vendor/, __pycache__/, .venv/.

  • Editor / IDE config that is user-specific.vscode/, .idea/, *.swp.

  • OS-generated files.DS_Store (macOS), Thumbs.db (Windows).

  • Logs and runtime files*.log, *.pid.

  • Secrets.env, *.key, anything with credentials.

  • Caches and temp files*.tmp, .cache/, coverage/.

Creating a .gitignore

Make one at the root of your repo

Bash
touch .gitignore
# Then add patterns, one per line
echo "node_modules/" >> .gitignore
echo ".env" >> .gitignore
echo "*.log" >> .gitignore

git add .gitignore
git commit -m "Add .gitignore"
A typical Node.js .gitignore

.gitignore

Text
# Dependencies
node_modules/
npm-debug.log*
yarn-error.log

# Build output
dist/
build/
.next/
out/

# Environment
.env
.env.local
.env.*.local

# Editors
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Coverage
coverage/
*.lcov

# Misc
.cache/
*.tmp
*.log
Basic pattern rules
  • Blank lines are ignored.

  • Lines starting with # are comments.

  • *.log — match any file ending in .log, anywhere in the repo.

  • /build — match build at the repo root only.

  • build/ — match a directory named build anywhere.

  • !important.log — re-include this file even though *.log would match it.

  • **/ — match across any number of directories.

Where .gitignore lives

You can place a .gitignore at any level. Patterns are evaluated relative to the directory where the .gitignore sits, and they apply to files in that directory and its children.

Nested .gitignore

Text
my-project/
├── .gitignore               ← project-wide rules
├── src/
│   ├── .gitignore           ← rules only for src/
│   └── component.js
└── docs/
    └── .gitignore           ← rules only for docs/
Other ignore mechanisms
  • ~/.config/git/ignore (or ~/.gitignore_global) — a per-user file. Useful for things like .DS_Store that you never want in any repo.

  • .git/info/exclude — like .gitignore but private to your clone. Not committed.

  • .gitignore checked into the repo — the shared rules everyone gets.

Configure a global .gitignore

Bash
git config --global core.excludesFile '~/.gitignore_global'

# Then list things you personally never want in any repo:
echo ".DS_Store"   >> ~/.gitignore_global
echo "*.swp"       >> ~/.gitignore_global
echo ".idea/"      >> ~/.gitignore_global
Already-tracked files are not auto-ignored
Warning
Adding a pattern to `.gitignore` does NOT untrack files Git is already tracking. The rule only stops *new* matching files from being added.

Stop tracking a file that's already in the repo

Bash
# 1. Add the pattern to .gitignore
echo ".env" >> .gitignore

# 2. Remove the file from the index (keep on disk)
git rm --cached .env

# 3. Commit
git commit -m "Stop tracking .env"
Check why a file is or isn’t ignored

Bash
git check-ignore -v node_modules/
# .gitignore:1:node_modules/   node_modules/

git check-ignore -v src/util.js
# (no output — not ignored)

check-ignore -v tells you which rule in which file matched — invaluable for debugging mysterious .gitignore behaviour.

Negating with !

Re-include specific files

Text
# Ignore all .log files…
*.log

# …except this one, which we DO want to commit
!important.log

# Ignore everything in dist/
dist/*

# …but keep dist/.keep (which marks the folder)
!dist/.keep
Order matters
Rules are applied top to bottom. A `!pattern` only un-ignores a file if its parent directory was *not* already ignored. Otherwise the file is never even looked at.
Ignoring an empty folder

Git only tracks files, not folders. If you want an empty directory in the repo, put a placeholder inside (commonly called .gitkeep). See the “Tracking Empty Folders” page.

Templates and generators
  • https://github.com/github/gitignore — official template repo: pick a language or framework, copy its .gitignore.

  • https://www.toptal.com/developers/gitignore — generate combined .gitignore for multiple stacks at once.

  • npx gitignore — CLI generator backed by the github/gitignore templates.

Common mistakes
  • Forgetting to commit .gitignore itself — the file must be tracked or teammates do not get the same rules.

  • Putting absolute paths in .gitignore — paths are relative to the file, not your filesystem.

  • Expecting .gitignore to scrub already-tracked files — it does not. Use git rm --cached.

  • Committing secrets first, then adding .gitignore — the secret is still in history. Rotate it and use git filter-repo to scrub.

Tip
Start every new project with a `.gitignore` *before* your first commit. If you start without one and accidentally commit `node_modules/`, expect a long evening of `git filter-repo` and explanations to your team.