A .gitignore file tells Git which files not to track: dependencies, build output, logs, editor files, and, most importantly, secrets like .env files. A good .gitignore keeps the repository small, the history clean, and credentials off GitHub.
Pattern syntax
| Pattern | Matches |
|---|---|
*.log |
Any .log file, in any directory |
node_modules/ |
Directory node_modules anywhere (trailing / = directories only) |
/dist |
dist only at the repository root |
build/*.tmp |
.tmp files directly in build/ |
**/cache/ |
cache directories at any depth |
docs/**/*.pdf |
PDFs anywhere under docs/ |
!keep.log |
Negation: don’t ignore this file |
# |
Comment |
Rules are read top to bottom, and the last matching rule wins. You can’t re-include a file if its parent directory is ignored. Ignore the contents instead:
logs/*
!logs/.gitkeep
A practical .gitignore for a web project
# secrets and environment
.env
.env.*
!.env.example
*.pem
*.key
# dependencies
node_modules/
vendor/
.venv/
# build output
dist/
build/
.next/
coverage/
# logs and runtime
*.log
tmp/
*.pid
# OS and editors
.DS_Store
Thumbs.db
.idea/
.vscode/*
!.vscode/extensions.json
# Docker and local data
docker-compose.override.yml
data/
Commit an .env.example with placeholder values, so others know which variables exist. See secrets management.
GitHub’s github/gitignore repository has templates for most languages and frameworks. gitignore.io (now part of Toptal) generates combined files.
Global ignores (your machine only)
Editor and OS files are personal. Put them in a global ignore file instead of every repository:
git config --global core.excludesfile ~/.gitignore_global
printf '.DS_Store\n.idea/\n*.swp\n' >> ~/.gitignore_global
Per-repository local ignores that shouldn’t be shared go in .git/info/exclude.
Already tracked? Untrack it
.gitignore only affects untracked files. If a file is already committed, ignoring it does nothing until you remove it from the index:
git rm --cached .env
git rm -r --cached node_modules
git commit -m "Stop tracking .env and node_modules"
The files stay on disk, but Git stops tracking them.
If a secret was ever committed, it’s still in history. Rotate the secret (change the password, revoke the key) immediately. Then optionally remove it from history with git filter-repo, or BFG, and force-push. See GitHub Actions secrets.
Debug ignore rules
git check-ignore -v path/to/file # which rule (file and line) ignores it
git status --ignored # list ignored files
git ls-files -ci --exclude-standard # tracked files that match ignore rules
Related ignore files
.dockerignore: keeps files out of Docker build contexts (same idea, with slightly different rules). Always exclude.git,node_modulesand.env. See Dockerfile tutorial..gitattributes: line endings, LFS tracking, and diff settings. See Git LFS.
Quick reference
| Task | Command / pattern |
|---|---|
| Ignore directory | name/ |
| Root only | /name |
| Re-include | !file (parent not ignored) |
| Global ignores | core.excludesfile |
| Untrack a file | git rm --cached <file> |
| Why ignored? | git check-ignore -v <file> |
Related: Git hooks and Git commands cheat sheet.