Mihai Dinculescu had a permanently dirty working tree, on purpose. His scratch files — markdown notes, agent plans, that kind of thing — were untracked and stayed untracked, because the only way he knew to ignore a file was .gitignore, and .gitignore gets committed. Pushing the silly filename he picked for his private notes into a shared repository felt unclean, so he did nothing and the files piled up.
Then a coding agent asked, unprompted, whether it should add them to .git/info/exclude. His reaction was the useful part of the post: what is that?
Git reads ignore patterns from three places, all with the same syntax
.gitignore— in any directory, affects everyone who clones the repo, committed..git/info/exclude— affects only this clone, never committed, lives inside.git.core.excludesFile— every repo on this machine, default~/.config/git/ignore, not committed.
How the split should be used
.gitignore: build output and local environments —target/,__pycache__/,.venv/,.env. Things every clone needs to ignore..git/info/exclude: your own scratch files that the project has no business knowing about. It cannot be committed even by accident, and nobody else ever sees it.- Global excludes: editor and OS clutter —
.idea/,.vscode/,Thumbs.db,.DS_Store. Which has no business appearing in most project.gitignorefiles, and yet it does.
The mechanics
echo 'plans/' >> .git/info/exclude
mkdir -p ~/.config/git && echo '.DS_Store' >> ~/.config/git/ignore
- Patterns are plain text and match relative to the repository root, exactly as in a top-level
.gitignore. - Git reads
~/.config/git/ignoreautomatically if it exists;git config --global core.excludesFile <path>points it somewhere else. - In a linked worktree
.gitis a file, not a directory, so use"$(git rev-parse --git-common-dir)/info/exclude", which resolves correctly from the main repo or any worktree. - Ignore rules never apply to files that are already tracked —
git statusonly goes quiet for files git has never seen.
One caveat he flags for anyone whose scratch files are agent plans: Claude Code leaves ignored files out of its @ autocomplete, so they vanish from the picker. "respectGitignore": false in settings.json brings them back; it only affects autocomplete, not what the tool can read.
The line worth keeping is his own explanation of why the gap existed: git is the tool most of us learned by accident, some of us more fortunately than others. Three files, one syntax, and two decades of collective not reading the manual.