TL;DR: Your .gitignore file tells Git which files not to track. Use it to keep build artifacts, local config, secrets, and OS/IDE clutter out of your history. Master a few rules—globs, directory patterns, and negations—and you’ll avoid noisy diffs, oversized clones, and accidental secret leaks.
Why .gitignore matters
A tidy repository helps everyone: faster clones, clearer diffs, fewer merge conflicts, and safer collaboration. Without a good .gitignore, you risk committing:
- Build output (e.g.,
dist/,bin/,target/) - OS junk (e.g.,
.DS_Store,Thumbs.db) - IDE metadata (e.g.,
.idea/,.vscode/) - Local config and secrets (e.g.,
.env,*.local.yml) - Large generated assets (e.g., reports, caches)
✅ Rule of thumb: If it’s reproducible or machine‑generated, it probably belongs in
.gitignore.
The basics: how .gitignore works
A .gitignore file lives at the root of your repository (you can also put additional ones in subdirectories). Each line is a pattern that matches files or folders to ignore.
Common pattern types
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 1) Exact file names .env # 2) File extensions *.log *.tmp # 3) Directories (trailing slash) node_modules/ build/ # 4) Globs cache/** # everything under cache/ assets/**/*.map # any .map inside assets at any depth # 5) Negation (override an ignore) logs/* !logs/.keep # keep a placeholder file so the folder exists |
Notes
#starts a comment- A leading
/anchors to the directory of the.gitignore **matches across directories;*matches within a single path segment- Order matters: later rules can override earlier ones
- To match a literal
#, prefix with\#; to match a literal!, prefix with\!
Repo‑level vs user‑level ignores
You have three places to ignore files:
- Repo
.gitignore— checked in and shared with the team. Use for project‑wide rules. .git/info/exclude— local to your clone. Good for machine‑specific files you never want to share.- Global ignore — configured once per machine (e.g., macOS junk, editor swap files):
|
1 2 3 4 5 6 7 8 |
# create a global ignore file git config --global core.excludesfile ~/.gitignore_global # add patterns to ~/.gitignore_global, e.g. *.swp .DS_Store Thumbs.db |
Tip: Keep secrets out of everywhere. Use secret managers or environment variables instead of committing credentials.
Language & framework starter snippets
Use these as a base, then customize for your stack.
Node.js / Front‑end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# dependencies node_modules/ # build outputs .next/ .nuxt/ dist/ build/ coverage/ # package managers .pnpm-store/ .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions # tooling .eslintcache .cache/ # env .env .env.local .env.*.local # misc *.log *.pid *.pid.lock |
Python
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# bytecode & caches __pycache__/ *.py[cod] *.pyo # virtual envs .venv/ venv/ .env/ # packaging build/ dist/ *.egg-info/ # test & tools .coverage .pytest_cache/ .mypy_cache/ # notebooks .ipynb_checkpoints/ |
PHP / Composer / WordPress
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# vendor & builds /vendor/ composer.lock # optional: ignore if libs are locked elsewhere # WordPress wp-content/uploads/ wp-content/cache/ wp-content/upgrade/ # configs (sample is tracked; real creds are not) wp-config.php !wp-config-sample.php # IDE/OS .idea/ .vscode/ .DS_Store |
Java
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# builds /target/ /build/ # IDEs *.iml .idea/ .project .classpath .settings/ # tooling .gradle/ .mvn/ |
Need more? Start with templates from your framework’s docs or generate a base with
gitignoretemplates and then tailor it to your repo.
Advanced patterns & pitfalls
“I added it to .gitignore, but it still shows up!”
.gitignore only affects untracked files. If a file is already committed, tell Git to stop tracking it without deleting your working copy:
|
1 2 3 |
git rm --cached path/to/file # then commit the change |
Keep a folder, ignore its contents
|
1 2 3 |
static/* !static/.keep |
Use an empty .keep (or .gitkeep) file to ensure the directory exists in the repo.
Don’t accidentally ignore too much
Anchoring avoids surprises:
|
1 2 3 4 5 6 |
# ignore only the repo‑root logs folder /logs/ # ignore any folder named logs, anywhere logs/ |
Secrets & .env
Never commit live credentials. Prefer environment variables or secret stores. If a secret did slip in, rotate it immediately and rewrite history only if necessary.
Git LFS & generated binaries
Large artifacts (videos, datasets, PSDs) bloat your repo. If you must version them, use Git LFS and still ignore transient outputs.
Debugging ignore rules
Use check-ignore to see which rule is catching a path:
|
1 2 |
git check-ignore -v path/to/file |
Team conventions that scale
- Commit your
.gitignoreearly: initialize it with your first commit. - Document special cases: leave comments explaining non‑obvious rules.
- Prefer whitelisting via negation for folders that need structure but not contents.
- Review PRs for noisy files: add new ignores as the project evolves.
- Environment parity: align with CI/CD (e.g., what your build pipeline produces should also be ignored locally).
FAQ
Q: Should I ignore composer.lock / package-lock.json?
A: Most app teams commit lockfiles for reproducible builds. Libraries often don’t. Align with your deployment strategy.
Q: Can I have multiple .gitignore files?
A: Yes. .gitignore files in subdirectories apply to those subtrees and can refine/override root rules.
Q: What about monorepos?
A: Keep a concise root .gitignore (OS/IDE/common) plus package‑level .gitignore files for framework‑specific outputs.
Wrap‑up
A well‑tuned .gitignore keeps your repository lean, secure, and pleasant to work in. Start simple, comment generously, and evolve it with the project.
Questions or suggestions? Drop a comment or reach out to the Reliable Penguin team.




