gitignore Generator
Compose a .gitignore from language and tool presets. Explains why each block exists, and what to do about files you already committed.
Languages
Frameworks
Tooling
Operating systems
Editors
Pick at least one preset above and the file appears here.
Key Takeaways
- .gitignore only affects untracked files. A file that was committed once keeps being tracked no matter what rule you add afterwards.
- To stop tracking something already committed, run
git rm --cached <file>and commit. The--cachedflag is what keeps the file on disk. - Selecting overlapping presets would normally repeat
node_modules/three times; this generator drops every repeat and keeps the first occurrence. - If a secret reached the history, rotate it. Deleting the file in a later commit does not remove the value from earlier commits.
The file that gets committed once and haunts the repo
On day one somebody types git add . and node_modules, .env and .DS_Store all land in the index. A week later someone adds a .gitignore and expects them to disappear. They do not. This is not a bug: .gitignore tells Git which files to leave alone when it encounters them for the first time. It says nothing about files Git already knows.
So whatever state a file was in before you wrote the rule is the state it stays in. Tracked stays tracked, shows up in git status on every edit, and rides along in every commit until you intervene directly.
The command that actually untracks a file
The fix is to remove the file from the index. The --cached flag is the load-bearing part: without it, the same command deletes the file from your working tree too, and doing that to a .env you have no backup of ends the afternoon.
# A single filegit rm --cached .envgit commit -m "chore: stop tracking .env" # An entire directorygit rm -r --cached node_modulesgit commit -m "chore: stop tracking node_modules" # Re-evaluate the whole repo against a freshly updated .gitignoregit rm -r --cached .git add .git commit -m "chore: apply gitignore rules"Warning
git status before committing: if an ignore pattern is too broad, a real source file will show up as deleted and it is far easier to notice now than three commits later.Pattern syntax
Most rules are ordinary globs, but four constructs change the meaning substantially and are routinely mixed up.
| Pattern | Matches | Does not match |
|---|---|---|
| build/ | A directory named build at any depth | A file named build |
| /build | Only build at the repository root | src/build |
| *.log | Any .log file in any directory | A directory named logs/ |
| !important.log | Re-includes a file an earlier rule excluded | Anything, if its parent directory is ignored |
| docs//*.pdf | PDFs at any depth under docs | PDFs outside docs |
Negation carries one trap. If a parent directory is itself ignored, you cannot re-include a file inside it: Git never descends into an excluded directory, so it never sees the exception. That is why the correct form is .vscode/* followed by !.vscode/settings.json, never .vscode/ followed by an exception. The VS Code preset keeps that ordering, and the dedupe pass never separates a negation from the rule it modifies.
Secrets and what to do when one leaks
.env appears in nearly every preset because of what is usually inside it: a database password, a signing key, an API token. The real problem is never the file, it is the history. Once .env has been pushed, the value lives in a commit, and deleting the file later does not remove it. Forks, clones, CI caches and GitHub's own archives all keep that commit reachable.
The only reliable response is rotation. Revoke the old credential at the provider, issue a new one, and put it in your runtime environment and CI secret store rather than a file. Rewriting history with git filter-repo or BFG is available if you want it, but it changes every commit hash, forces everyone on the team to re-clone, and does nothing about anyone who already pulled the secret.
Global gitignore for editor noise
Lines like .DS_Store, *.swp and .idea/ in a shared repository tend to start an argument, because they describe a person's setup rather than the project. Instead of pushing your own tooling into someone else's file, keep it in a global ignore file:
git config --global core.excludesfile ~/.gitignore_global # contents of ~/.gitignore_global.DS_Store*.swp.idea/.vscode/The repository .gitignore is then free to describe only what the project itself produces: build directories, dependency trees, caches. That separation is also why the presets here emit languages and frameworks first and push the OS and editor blocks to the bottom, so the rules a reviewer cares about are at the top of the file.
Frequently Asked Questions
- I already committed a file. How do I remove it?
- Add the pattern to .gitignore, then run
git rm --cached <path>and commit. Add-rfor a directory. Without--cachedthe file is deleted from disk as well, so never drop that flag. After this the file stops being tracked, though it remains visible in earlier commits. - My .env was pushed to GitHub. Is deleting it enough?
- No. Deleting creates a new commit; the earlier one still contains the readable value. Rotate every credential in that file first: revoke at the provider and issue new values. History rewriting with git filter-repo or BFG is secondary cleanup, and because it rewrites every hash it forces the team to re-clone while offering no protection against someone who already copied the key.
- Does .gitignore work retroactively?
- It does not. The rules apply only to untracked files. Existing commits are unchanged and files sitting in the index stay there. The only way to get a retroactive effect is to remove them from the index yourself with git rm --cached.
- Global gitignore or the one in the repository?
- The dividing line is whether the file comes from your toolchain or from the project. Editor directories, OS metadata and personal scratch files belong in the global file, because a colleague on a different setup never produces them. Build output, dependency directories and environment files belong in the repository file, because everyone who clones it will generate them.
- Why is my ignored file still showing up?
- Almost always because it is already tracked. Run
git check-ignore -v path/to/file: it prints which rule matched and on which line. No output means no rule matches. Output plus a file still in git status means it sits in the index and needs git rm --cached. The third possibility is a negation inside an ignored directory, which Git never evaluates.