Where should Git ignore rules for editor and OS files live instead of the repo .gitignore?
answer
- Ask who else produces this file
- Three places, only one of them is shared
- One file lives inside the .git directory
- Precedence: repository outranks personal
basics
~10 sPersonal, cross-repository rules belong in the file named by core.excludesFile; personal rules for one clone belong in .git/info/exclude. The committed .gitignore should hold only what every contributor produces, such as build output.
solid answer
~50 sGit reads ignore patterns from several sources, and choosing the right one is a team-hygiene decision. Rules that everyone's build produces, such as `target/` or `dist/`, belong in the committed `.gitignore` so they are shared and reviewable. Rules that reflect *your* editor or operating system belong in your personal file named by `core.excludesFile`, set once with `git config --global core.excludesFile ~/.gitignore_global`; when that setting is unset Git falls back to `$XDG_CONFIG_HOME/git/ignore`, in practice `~/.config/git/ignore`. Rules that are personal but specific to one clone, like a scratch directory, go in `.git/info/exclude`, which is never committed and is lost if you re-clone. Precedence runs highest to lowest: patterns given on the command line, then per-directory `.gitignore` files with the deepest winning, then `.git/info/exclude`, then the global excludes file. Because the repository file outranks the personal ones, a project can re-include with `!` something your global rules hide.
code
bash · 3 linesgit config --global core.excludesFile ~/.gitignore_global
printf '.DS_Store\n.idea/\n*.swp\n' >> ~/.gitignore_global
printf 'scratch/\n' >> .git/info/excludego deeper
Know that there is more than one ignore file: the committed one in the repository, plus personal ones. Editor noise belongs in your own configuration, not in the project's file.
Name all three locations, the config key that points at the global file, and the precedence order in which Git consults them, including that a deeper .gitignore beats a shallower one.
Show the operational reasoning: personal rules explain machine-to-machine differences and are invisible to a fresh automated checkout, so anything a build depends on must be committed. Diagnose with the verbose check-ignore output.
Own the standard across repositories: a short reviewable project file scoped to build artifacts, personal noise pushed into per-user configuration, and onboarding docs that set the global file once so the shared file never becomes a junk drawer.
## The four sources For any given untracked path, Git consults, in decreasing order of precedence: 1. **Patterns supplied on the command line**, for commands that accept them. 2. **`.gitignore` files** in the path's own directory and every parent up to the top of the work tree, with files closer to the path overriding files further up. 3. **`$GIT_DIR/info/exclude`**, normally `.git/info/exclude`, which lives inside the repository directory and is never transferred by clone, fetch or push. 4. **The file named by `core.excludesFile`**, the per-user global list. If the setting is unset, Git uses `$XDG_CONFIG_HOME/git/ignore`, falling back to `$HOME/.config/git/ignore`. Within each source the last matching line still wins; the ordering above resolves conflicts *between* sources. ## Which rule goes where The deciding question is: who else produces this file? - **Everyone who builds the project** produces `target/`, `node_modules/`, `*.pyc`, coverage reports. These belong in the committed `.gitignore`, close to where they are generated. Reviewers can see them, and a new contributor gets them for free. - **Only you** produce `.idea/`, `.vscode/`, `.DS_Store`, swap files, and directories your particular editor drops everywhere. These belong in your global excludes file. Putting them in the repository is a small tax on everyone: the file grows a section for every tool anyone has ever used, and the list quietly becomes unmaintainable. - **Only you, and only here**, covers a `scratch/` directory or a local profiling dump in one clone. That is what `.git/info/exclude` is for. It is invisible to everyone else and disappears if you delete the clone, which is exactly the intended lifetime. ## Why precedence matters in practice Because the repository's `.gitignore` outranks both personal sources, a project can override an over-broad personal rule. If a developer globally ignores `*.log` and the project genuinely tracks a fixture named `sample.log`, the repository file can re-include it with `!sample.log`. The reverse is not possible: a personal file cannot override the project. This asymmetry is deliberate. Shared correctness beats personal convenience, and it means a project can be made self-consistent regardless of who checks it out. ## The failure mode this prevents The common pathology is a repository `.gitignore` that has grown into a catalogue of editors, operating systems and personal tools, contributed to by everyone who ever joined. Nobody dares delete a line because nobody knows who needs it, and the broad patterns inside it eventually hide a real source file. Splitting by ownership keeps the shared file short enough to read in one screen and to reason about during review. ## Diagnosing across sources When a file behaves differently on two machines, the usual culprit is a personal rule. `git check-ignore -v <path>` prints the source file for the deciding rule, so it names the global file or `.git/info/exclude` explicitly. That single command distinguishes "the project hides this" from "your machine hides this", which is exactly the ambiguity that wastes time in a debugging session. ## Operational notes - `.git/info/exclude` is not backed up and not transferred; treat it as scratch, not as configuration you rely on. - Setting `core.excludesFile` is a per-user config change, so it can be set at global scope once and applies to every repository you clone afterwards. - Automation that checks out the repository fresh sees only the committed rules. If a build step depends on something being ignored, that rule must be in the repository, not in anyone's personal file. - Because ignore rules never apply to tracked paths, moving a rule between sources changes nothing for files already in the index; those still need untracking.
- Which of these ignore sources survives deleting and re-cloning the repository?Only the committed `.gitignore` files and your global excludes file. `.git/info/exclude` lives inside the repository directory, so it is destroyed with the clone and is never pushed or fetched. Treat it as scratch space for rules you can afford to lose, and put anything you would be annoyed to re-type into the global file instead.
- A file is ignored on one developer's machine but shows up as untracked on another. How do you explain it?Almost certainly a personal rule. Run `git check-ignore -v` on the path on the machine where it is hidden: if the reported source is the global excludes file or `.git/info/exclude`, the project never ignored it. Decide deliberately whether the rule belongs in the committed file so that everyone, including automated checkouts, behaves the same way.
saying these in an interview costs you the question
- Adds every editor and OS pattern to the repo .gitignore
- Thinks .git/info/exclude is shared with collaborators
- Expects a personal global rule to override the project file
- Believes a global rule applies during a fresh CI checkout
- Assumes moving a rule fixes an already-tracked file