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 folders —
node_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
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
# 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— matchbuildat the repo root only.build/— match a directory namedbuildanywhere.!important.log— re-include this file even though*.logwould 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
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_Storethat you never want in any repo..git/info/exclude— like.gitignorebut private to your clone. Not committed..gitignorechecked into the repo — the shared rules everyone gets.
Configure a global .gitignore
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
Stop tracking a file that's already in the repo
# 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
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
# 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
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
.gitignorefor multiple stacks at once.npx gitignore— CLI generator backed by the github/gitignore templates.
Common mistakes
Forgetting to commit
.gitignoreitself — 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
.gitignoreto scrub already-tracked files — it does not. Usegit rm --cached.Committing secrets first, then adding
.gitignore— the secret is still in history. Rotate it and usegit filter-repoto scrub.