What a .gitignore file does
When you work with Git, not every file in your folder should be versioned. Downloaded dependencies (node_modules/), build output (dist/, build/), system temp files (.DS_Store) and above all credentials (.env) add nothing to the history and, in the worst case, leak secrets. The .gitignore is a list of patterns that tells Git: "these files exist on my disk, but do not track them or show them as pending changes".
This tool combines real templates per technology. If you check Node, Python and macOS, it joins the three blocks, removes duplicate lines and returns a single file organized in sections with # --- Node --- headers so you know where each rule comes from.
Repo .gitignore vs global
There are two places to put rules. The repo .gitignore lives in the project root, is versioned and shared with the whole team: this is for project-specific rules (build folders, dependencies, artifacts). The global .gitignore lives on your machine and applies to all your repos; this is where your personal stuff should go, like editor or OS files that not everyone on the team necessarily uses. You set it up once:
git config --global core.excludesfile ~/.gitignore_global The practical rule: project-specific things go in the repo; things that depend on your setup (editor, OS) go in the global one.
Rule order and precedence
Git evaluates patterns top to bottom and the last match wins. This matters when you use negations with !. For example, to ignore all logs except one:
*.log
!important.log If you flip the order, the *.log rule ignores important.log again and the negation is useless. Watch out for an important limitation: you cannot re-include a file if its parent folder is already ignored. If you have logs/, an !logs/keep.txt will not work; you must first ignore the contents with logs/* and then negate the specific file.
How patterns are written
*.log→ all files ending in.log, in any folder.build/→ the trailing slash means a folder named build./build→ the leading slash anchors the rule to the repo root.**/temp→ the double asterisk crosses any number of folder levels.!file→ the exclamation mark negates (re-includes) a previous pattern.# comment→ lines starting with # are comments and are ignored.
Common mistakes worth avoiding
- Committing
.envwith secrets. The most expensive mistake. If you already pushed it, deleting it is not enough: it stays in the history. You have to rotate the exposed credentials and, if needed, scrub the history. - Adding the rule after tracking the file.
.gitignoreonly affects untracked files. If the file is already in Git, rungit rm --cached fileand commit. - Ignoring
node_modules/but committing the lockfile. Correct: thepackage-lock.jsonoryarn.lockSHOULD be versioned; what you ignore is the dependencies folder, not the lockfile. - Using absolute paths. Patterns are relative to the repo, not to your disk.
/Users/you/project/distdoes not work;dist/does.
Reference: key patterns per stack
| Stack | Key patterns |
|---|---|
| Node | node_modules/, .env, dist/, npm-debug.log* |
| Python | __pycache__/, *.pyc, .venv/, *.egg-info/, .pytest_cache/ |
| Java | *.class, target/, *.jar, .gradle/ |
| Next.js | .next/, out/, .vercel |
| Django | *.sqlite3, media/, staticfiles/, local_settings.py |
| macOS | .DS_Store, .AppleDouble, Icon? |
| Windows | Thumbs.db, Desktop.ini, $RECYCLE.BIN/ |
| Linux | *~, .directory, .Trash-* |
| VS Code | .vscode/ (except shared settings) |
| JetBrains | .idea/, *.iml, out/ |