Why a pasted template goes stale
A language template is a snapshot of what one toolchain wrote to disk on the day someone wrote it down. Tool caches come and go — a directory that did not exist two years ago is now several hundred megabytes on every developer machine, and a directory that used to matter has been renamed. Because the file is append-only in practice, nothing ever gets removed, and the entries pile up until nobody can tell which lines are load-bearing.
The version built here is smaller on purpose. It covers the output directories, dependency directories and caches that every project in that stack produces, and it leaves out the long tail of patterns for tools you are probably not using. If a stray file shows up in git status later, adding one line to a file you understand is easy. Pruning a two-hundred-line inheritance is not.
The three patterns people argue about
Lock files come first. A lock file records the exact versions that were installed, which is the entire point of having one, so ignoring it means two machines can build different software from the same commit. Nothing here ignores a lock file. The conventional exception is a published library, where the lock file describes the development environment rather than what a consumer will resolve — and even that convention has been shifting.
Build output is second. Ignoring dist/ is correct when the deploy step builds from source and wrong when the repository is the distribution channel. The blocks above include the common build directories and flag them, because the right answer depends on how the thing ships, not on what language it is written in.
Editor folders are third, and the honest answer is that they are half shared and half personal. A code style profile belongs to the team; a list of which files you had open does not. That is why the editor blocks ignore the folder with a trailing /* and then re-include specific files, rather than ignoring the folder outright.
How git actually decides
Patterns are read in order and the last one that matches a path determines the outcome, which is the opposite of how most people read a config file. A pattern with no slash matches at any depth. A pattern ending in a slash matches directories only. A leading slash anchors the pattern to the directory holding the .gitignore, and a pattern with a slash anywhere other than the end is anchored the same way. Two asterisks match across directory boundaries; one does not.
The rule that catches people is that git does not descend into an ignored directory at all. Once logs/ is ignored, git never looks inside it, so a later !logs/keep.txt has nothing to act on. Ignore the contents instead — logs/* — and the negation works, because the directory itself was never excluded.
Where else ignore rules live
A repository can have a .gitignore in any directory, and the nearest one wins for paths beneath it, which is a cleaner way to handle a monorepo than one enormous file at the root. Beyond the repository there are two more layers: .git/info/exclude, which is local to your clone and never committed, and a global ignore file configured with core.excludesFile. Personal preferences belong in those two. Your editor choice is not something every contributor should have to carry, and putting it in the global file is the tidiest way to stop that argument before it starts.
What this file cannot do for secrets
The credentials block reduces the chance of an accidental git add . picking up a key. It does nothing about a file that is already tracked, because ignore rules are only consulted for untracked paths, and it does nothing about history. If a credential has been committed, the file has to be removed from every commit that contains it and the credential itself has to be rotated, on the assumption that anyone with clone access already has it. Treat the block as a seatbelt, not as the reason it is fine to keep secrets in the working directory. If you need to check what a set of file permissions on a key actually allows, the chmod calculator and the permission explainer cover that side.
Related pages
Once the repository is tidy, the neighbouring jobs are usually documentation and release notes: the markdown table of contents generator for a long README, the changelog formatter for turning commit lines into release notes, and the semantic version comparator for deciding what the next tag should be. For environment files specifically, the env file converter handles the format itself.
Questions people ask
I added a pattern and the file is still showing up in git status.
Ignore rules are only consulted for files git is not already tracking. If the file was committed at any point, it stays tracked and the pattern is irrelevant to it. Run git rm --cached on the path, commit that removal, and from then on the ignore rule applies. If the file was never committed and still appears, run git check-ignore -v on the path — it prints which file and which line decided, which is usually a negation further down or a rule in a nested .gitignore.
Should node_modules or vendor really never be committed?
For the dependency directories in these blocks, the assumption is that a lock file plus an install step reproduces them, which is true for npm, pip, Composer and Bundler. Go vendoring is the deliberate exception, because a vendor directory only helps if it is in the repository, which is why nothing here ignores it. If your build has no network access at deploy time, committing dependencies is a legitimate choice — it just needs to be a choice rather than an accident.
Why are the negation lines placed where they are?
Git evaluates patterns in order and the last match wins, so a negation only works if it comes after the pattern it is undoing. That is why the editor block writes .vscode/* first and the re-included files after it, and why the credentials block puts the example-file negations below .env.*. Moving a negation above its pattern silently disables it, with no error anywhere.
Can I use this for a repository that already has a large .gitignore?
Generate the file, then diff it against what you have rather than replacing outright. The existing file almost certainly contains a few project-specific lines that no template would produce — a generated asset directory, a data dump, a path that one person keeps committing by mistake. Those are the lines worth keeping. The generic blocks are the ones worth replacing.
Does anything I tick get sent anywhere?
No. The blocks are constants inside the page and the file is assembled in JavaScript in the tab you have open. No request is made, nothing is stored, and the tool has no idea what your repository contains — it only knows which boxes are ticked.