Select your stack
What .gitignore does (and doesn't do)
.gitignore tells Git which files and directories to skip when staging changes. Each line is a pattern; matching paths never get added to commits, never show up in git status, and never accidentally get pushed. The file lives at the repo root (and can be supplemented by additional .gitignore files in subdirectories that scope to that subtree only).
What it doesn't do: remove files already tracked. If you accidentally committed node_modules, adding it to .gitignore won't untrack it — you still need to run git rm -r --cached node_modules and commit the deletion. After that, the ignore rule prevents re-staging.
Pattern syntax — the things that confuse everyone
- Leading slash anchors to repo root.
/buildmatches only./build, notsrc/build. Without the slash,buildmatches anywhere. - Trailing slash means directory only.
logs/matches the directory but not a file namedlogs.logsmatches both. - Double-star matches any depth.
**/node_modulesmatches at any nesting level.logs/**matches everything inside thelogsdirectory. - Negation with
!re-includes.*.logfollowed by!important.logignores all logs except that one. Order matters — the negation has to come after the pattern it overrides. - Comments start with
#. A literal hash at the start of a filename can be escaped:\#weird-file. - Whitespace at end of line is included in the pattern unless escaped.
logs(trailing space) does not matchlogs. Save with no trailing whitespace.
What should ALWAYS be in your .gitignore
- Secrets:
.env,.env.local,credentials.json,*.pem, anything with API keys or passwords. Once a secret is committed, it's effectively leaked — git history is forever. Rotate the key, then update gitignore. - Dependency directories:
node_modules/,vendor/,.venv/,target/. These are reproducible from lockfiles — never commit them. - Build artifacts:
dist/,build/,*.exe,*.dll, compiled binaries. Generate on demand. - OS metadata:
.DS_Store(macOS),Thumbs.db(Windows),desktop.ini. Polluting collaborators' repos. - IDE settings (most of the time):
.vscode/,.idea/. Per-developer preferences shouldn't be shared. Exception: shared run configurations, project-wide debugger setups — those go in a separate committed file. - Logs and runtime data:
*.log,tmp/,cache/.
What should NOT be in your .gitignore
- Lock files.
package-lock.json,yarn.lock,Gemfile.lock,poetry.lockshould all be committed. They guarantee reproducible builds across machines. Ignoring them defeats the entire point of having lockfiles. - Test snapshots. Jest's
__snapshots__and similar should be committed and reviewed in diffs. - Editor configs that are project-scoped.
.editorconfigat the repo root standardizes indentation across editors — commit it. - CI configuration.
.github/workflows/,.gitlab-ci.yml— these define what runs in CI. Always commit.
Global gitignore — for files Git should never see anywhere
Some files (your editor's swap files, system metadata) belong in a global gitignore that applies to every repo on your machine, not the per-project one. Set it up once:
git config --global core.excludesFile ~/.gitignore_global # Then put things like this in ~/.gitignore_global: .DS_Store *.swp .vscode/ .idea/
This way, projects you contribute to don't get cluttered with rules for your specific tooling — and you don't have to re-add the same OS/editor patterns to every new repo.
Common use cases
- Initialize a new repo with the right ignore patterns for your stack
- Audit and refresh a stale .gitignore missing newer tooling (.next/, .turbo/, .ruff_cache/)
- Combine multi-language (e.g. monorepo) ignore rules without duplication
- Generate a per-OS section to add to an existing project
Frequently asked questions
Will adding a file to .gitignore remove it from Git?
No. <code>.gitignore</code> only prevents <em>new</em> files from being staged. If you already committed something (e.g. node_modules), also run <code>git rm -r --cached node_modules</code> followed by a commit.
Should I commit package-lock.json / yarn.lock?
Yes — always. Lockfiles guarantee reproducible builds. Ignoring them is one of the most common .gitignore mistakes. Same for Gemfile.lock, poetry.lock, Cargo.lock.
Global vs per-project .gitignore?
Per-project (in the repo) is for files specific to that stack. Global (<code>~/.gitignore_global</code>, configured via <code>git config --global core.excludesFile</code>) is for files specific to YOUR setup — editor swap files, OS metadata — that no project needs.
Why is .vscode/ included in the VS Code template?
Per-developer settings shouldn't pollute shared repos. If you have project-wide configuration the whole team should use (launch.json, recommended extensions), commit those specific files via negation rules: <code>.vscode/*</code> followed by <code>!.vscode/settings.json</code>.
Does order of rules matter?
Yes for negation rules. <code>!important.log</code> must come <em>after</em> <code>*.log</code> to override it. For ordinary ignore patterns, order doesn't affect behavior — but grouping related patterns together makes the file easier to maintain.