Three Ways to Ignore Files in Git (Beyond .gitignore)

TL;DR
Most developers only know .gitignore, but Git offers two other ignore mechanisms for local workflows and machine-wide patterns.
Last updated: October 13, 2026 (commands re-checked against the current git documentation)
A post on Hacker News today resurfaced something that many developers overlook: .gitignore is not the only way to ignore files in Git. There are actually three distinct mechanisms, each designed for different use cases. Understanding when to use which can clean up your repos and avoid awkward pull request feedback.
The Three Levels of Git Ignore#
1. .gitignore (Shared, Committed)#
The familiar option. Whatever patterns you add to .gitignore get committed to the repository and apply to everyone who clones it.
$ cat .gitignore
node_modules/
dist/
.env
Use for: Build artifacts, dependencies, environment files - anything project-specific that no contributor should commit.
2. .git/info/exclude (Local, Per-Repository)#
Located inside the .git directory, this file follows the same syntax as .gitignore but never gets committed. It's repository-specific and stays on your machine only.
$ cat .git/info/exclude
my-local-notes.md
scratch/
debug.log
Use for: Personal scratch files, local test data, IDE configs that only you use, Makefiles or scripts specific to your dev environment.
3. ~/.config/git/ignore (Global, Machine-Wide)#
A global ignore file that applies across every repository on your system. By default, Git looks for it at ~/.config/git/ignore, but you can point it elsewhere:
git config --global core.excludesFile ~/.gitignore_global
$ cat ~/.config/git/ignore
.DS_Store
Thumbs.db
*.swp
.idea/
Use for: OS-specific cruft like .DS_Store on macOS or Thumbs.db on Windows. Also useful for editor-specific files you use across all projects.
Debugging Ignore Rules#
When a file is being ignored and you're not sure why, Git has a built-in diagnostic:
git check-ignore -v myfile.txt
This outputs the file path, line number, and pattern responsible for ignoring the file. It's invaluable when you inherit a repo with complex ignore rules or when you're troubleshooting why something isn't showing up in git status.
The Tracked File Trap#
There is one case where ignore files will not do what developers expect: the file is already tracked. .gitignore, .git/info/exclude, and the global ignore file only stop untracked files from appearing in git status. They do not make Git forget a file that is already in the index.
That is why searches for this topic often drift into git update-index --skip-worktree and git update-index --assume-unchanged. Those commands are not more powerful ignore files. They are index hints for tracked paths, and they belong in a narrower bucket.
Use --skip-worktree when a tracked file needs a local-only value in your checkout, such as a sample config copied into a real config path:
git update-index --skip-worktree config/local.json
Undo it before committing a real change:
git update-index --no-skip-worktree config/local.json
Use --assume-unchanged even more sparingly. Git documents it as a performance hint for paths that are expensive to stat, not a workflow primitive for ignoring personal edits. If your real goal is "I changed this file locally and never want to commit it," prefer .git/info/exclude for untracked files or restructure the config so the tracked file imports a local override.
If you inherit a repo and suspect one of these flags is already set, inspect the index directly:
git ls-files -v | grep '^[a-zS]'
Uppercase S marks skip-worktree paths. Lowercase status markers can reveal assume-unchanged paths. Treat that output as a cleanup list, not as a pattern to spread across the team.
This distinction matters for agent-heavy repos too. When you are running parallel coding agents in worktrees, the cleanest setup is usually:
- shared generated outputs in
.gitignore - personal scratch files in
.git/info/exclude - machine-wide editor files in
~/.config/git/ignore - tracked-but-local config handled by templates, env files, or a documented
skip-worktreeexception
That keeps review queues focused on real code instead of accidental local state. It also pairs well with local coding agent workspaces, filesystem contracts for agent workspaces, and parallel coding agent merge discipline.
What HN Is Saying#
The Hacker News discussion surfaced some practical patterns from experienced developers:
The "attic" pattern. Several commenters add attic to their global ignore, then create an attic/ directory in any project for random files that should never be committed. One commenter takes this further by putting a .gitignore inside the attic/ directory containing just * - making the directory self-ignoring.
The scope debate. There's a split on whether IDE/editor-specific ignores belong in the repo's .gitignore or your personal global config. The pragmatic argument: adding .idea/ or .vscode/ to every project's .gitignore saves everyone the trouble of configuring their global ignore. The purist argument: a repo's .gitignore should only contain patterns relevant to the project itself.
Devcontainer edge case. One commenter pointed out that global ignore files don't survive devcontainer rebuilds - you need to bind-mount your config or explicitly persist it.
The Magit angle. Emacs users noted that Magit has native support for choosing between shared (.gitignore) and private (.git/info/exclude) ignores when pressing i on a file.
The Decision Framework#
Here's when to use each:
| Scenario | Use |
|---|---|
| Build output, dependencies, secrets | .gitignore |
| Personal scratch files in one repo | .git/info/exclude |
| OS/editor files across all repos | ~/.config/git/ignore |
| Tracked file with local-only edits | Usually redesign the config; use skip-worktree only as an explicit exception |
The key insight: if it's something every contributor would need to ignore, put it in .gitignore. If it's specific to your workflow but not the project, use the local or global options.
Why This Matters#
Bloated .gitignore files are a code smell. When a repo's ignore file contains 50 lines covering every IDE, editor, and OS under the sun, it suggests nobody is using the right tool for the job. The result is a file that's hard to maintain and hides project-specific patterns in noise.
Knowing about .git/info/exclude, the global ignore file, and the tracked-file boundary gives you cleaner repos and fewer "please remove your IDE config from the gitignore" code review comments. It is the same operational lesson behind Codex CLI resource budgets, permissions and rollback for AI coding agents, and GitKraken plus Claude Code workflows: local developer tooling should leave a small, obvious footprint in the repo.
FAQ#
Should I put .vscode/ or .idea/ in .gitignore?#
If the project intentionally shares editor configuration, commit the useful settings and ignore only machine-specific files. If the files are purely personal, prefer your global ignore file. Teams often still put common editor directories in .gitignore because it reduces accidental commits, but that is a convenience tradeoff, not a Git requirement.
Why is Git still tracking a file after I added it to .gitignore?#
Because .gitignore does not apply to files already tracked in the index. Remove the file from the index with git rm --cached path if it should stop being tracked for everyone, or redesign the config so local values live in an untracked override file.
When should I use git update-index --skip-worktree?#
Use it only for a documented local exception on a tracked file. It is not a replacement for .gitignore, and it can surprise you later when a real upstream change touches the same path.
Is assume-unchanged the same as skip-worktree?#
No. assume-unchanged is mainly a performance hint. skip-worktree is closer to a local working-tree override. For normal "do not commit this file" workflows, ignore files or config templates are easier to reason about.
Continue Reading#
- Best Free Developer Tools - free browser tools that pair with git and the terminal
- Best CLI Tools for Developers - command-line tools worth adding next to git
Sources#
- .gitignore Isn't the only way to ignore files in Git - Original article
- Hacker News Discussion - Community discussion
- Git Documentation: gitignore - Official Git manual page
- Git Documentation: git-check-ignore - Ignore rule diagnostics
- Git Documentation: git-update-index -
skip-worktreeandassume-unchanged - Stack Overflow: assume-unchanged vs skip-worktree - Search-intent reference for tracked-file confusion
Get the next deep dive like this in your inbox
One email a week on News and the rest of the AI dev stack. Free.
Read next on AI coding tools
Git Finally Gets a History Command Worth Using
Git history command: how the experimental fixup, reword and split subcommands in Git 2.54 and 2.55 replace scary interactive rebases, and what developers think.
5 min readGleam Moves to Tangled: What the ATProto Code Forge Means for Developers
Gleam moved to Tangled, an ATProto-based code forge. What Tangled offers, what HN said about it, and what you gain or lose by leaving GitHub.
6 min readClaude Cookbook: Anthropic's Official Playbook for Building with Claude
Anthropic launched the Claude Cookbook - 90+ practical guides from their engineers covering tool use, agent patterns, evals, and production deployment. The HN discussion debates whether cookbook resources still matter when you can just ask the AI.
7 min readNew here? Start with
Technical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.






