A .gitignore file lives in a Git repository and lists patterns of files Git should refuse to track. Anything matched by a .gitignore pattern is invisible to git status and git add, even when the file exists in the working tree. The tool above generates .gitignore files for common stacks; nothing leaves your machine.
Pattern syntax
A .gitignore pattern looks glob-like but has Git-specific extensions. The full reference is in the Git documentation; the patterns that come up daily:
| Pattern | What it matches |
|---|---|
node_modules | Any directory or file named node_modules anywhere in the repo |
node_modules/ | Same — but only when it’s a directory |
/node_modules | A node_modules only at the root of the repo |
*.log | Any file ending in .log, anywhere |
**/build | Any build directory, anywhere |
build/** | Everything inside any build directory |
!important.log | Negation — re-include important.log if it would otherwise be ignored |
# comment | A comment (lines starting with # are skipped) |
A trailing slash means “directory only.” A leading slash anchors the pattern to the location of the .gitignore file. Without a leading slash, the pattern is matched anywhere in the tree below the .gitignore.
Anchoring
node_modules ← anywhere in the tree
/node_modules ← only at the same level as this .gitignore
src/node_modules ← only at this exact path (relative to .gitignore)
The first form is the most common — it ignores all node_modules directories at any depth, which is what you almost always want.
Per-stack defaults
Different language ecosystems generate different “junk” files. Standard .gitignore patterns:
| Stack | Common entries |
|---|---|
| Node.js | node_modules, npm-debug.log*, .env, dist/, coverage/, .next/, .parcel-cache |
| Python | __pycache__/, *.py[cod], .venv/, *.egg-info/, .pytest_cache/, .mypy_cache/ |
| Java | *.class, target/, .gradle/, build/ |
| Go | binaries (no extension on Linux, .exe on Windows), *.test, *.out, go.work (vendor/ only if you don’t commit vendored modules) |
| Rust | target/, **/*.rs.bk (commit Cargo.lock — Cargo’s default since 2023) |
| Ruby / Rails | .bundle/, log/*.log, tmp/, vendor/bundle, coverage/, .byebug_history |
| .NET / C# | bin/, obj/, *.user, *.suo, .vs/ |
Each per-stack page on this site has the corresponding ignore list. See Python, Node, Java, Go, Rust, .NET / C#, Ruby / Rails.
OS and editor entries
Independent of language stack, every .gitignore typically also has:
# OS
.DS_Store # macOS Finder metadata
Thumbs.db # Windows thumbnail cache
ehthumbs.db
*.swp # Vim swap files
# Editors
.idea/ # JetBrains IDE
.vscode/ # VS Code (often kept; see below)
*.sublime-*
The .vscode/ directory is contentious. Some teams ignore it (per-developer preferences shouldn’t be shared); some commit it (shared launch configs and recommended extensions are useful). Pick a team convention.
Negation patterns
# Ignore the whole logs directory…
logs/
# …except keep the example log file
!logs/example.log
Negation re-includes a file. Two restrictions:
- A negated pattern can’t re-include a file from an ignored directory. If the parent dir is ignored, the file inside is ignored regardless of negation. To re-include, you have to not ignore the parent dir directly.
- Order matters. Later patterns override earlier ones. A negation has to come after the pattern it negates.
Files Git is already tracking
.gitignore only affects untracked files. If a file is already tracked, adding it to .gitignore doesn’t make Git stop tracking it. To remove it from tracking while keeping it in the working tree:
git rm --cached path/to/file
git commit -m "stop tracking accidentally-committed file"
This is the standard procedure for “I committed .env and now want it untracked.” The file stays in your working tree; Git stops watching it.
Global gitignore
Patterns specific to your machine (your editor’s swap files, your OS’s thumbnail cache) belong in a global gitignore, not in every project’s .gitignore:
git config --global core.excludesfile ~/.gitignore_global
Then edit ~/.gitignore_global to include .DS_Store, *.swp, etc. The project .gitignore is for project-relevant patterns (build outputs, dependencies); the global is for machine-relevant ones.
Common pitfalls
- Adding a pattern after committing a file. Doesn’t untrack. Use
git rm --cached(above). - Whitespace at end of pattern. A line ending with a space is a literal pattern that matches nothing useful. Many editors auto-trim; some don’t.
- Comments mid-line.
node_modules # the dependency dirignores a literal “node_modules # the dependency dir” path. Comments must be on their own line. - Using shell-style escaping.
.gitignorepatterns are not shell glob; quotes don’t help. To match a literal*, escape with\*. - Forgetting the trailing slash.
buildmatches both files and directories namedbuild;build/matches only directories. The latter is usually what you want.
For language-specific defaults, see the Python, Node, Java, Go, Rust, .NET, Ruby pages.