
TL;DR
Most developers only know .gitignore, but Git offers two other ignore mechanisms for local workflows and machine-wide patterns. Here's when to use each.
Last updated: June 24, 2026
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 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.
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.
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.
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.
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:
.gitignore.git/info/exclude~/.config/git/ignoreskip-worktree exceptionThat 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.
Newsletter
Get the weekly deep dive
Tutorials on Claude Code, AI agents, and dev tools, delivered free every week.
From the archive
Jun 19, 2026 • 8 min read
Jun 19, 2026 • 8 min read
Jun 19, 2026 • 8 min read
Jun 19, 2026 • 8 min read
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.
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.
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.
.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.
.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.
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.
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.
skip-worktree and assume-unchangedRead next
Oak rethinks version control for agentic workflows with virtual mounts, faster snapshots, and lower VCS-related token overhead. Here's what the HN community thinks about this Show HN.
8 min readA developer used OpenAI Codex to build a fully open-source WYSIWYG editor for TikZ figures. The technical approach and reception on Hacker News offer a useful case study in what agent-built software looks like when shipped.
7 min readEpic Games open-sourced Lore, a centralized version control system designed for binary-heavy game projects. It uses Merkle trees, on-demand file hydration, and native chunked storage to handle terabyte-scale repos that Git struggles with.
7 min readTechnical 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.
OpenAI's coding agent for terminal, cloud, IDE, GitHub, Slack, and Linear workflows. Reads repos, edits files, runs comm...
View ToolMost popular LLM framework. 100K+ GitHub stars. Chains, RAG, vector stores, tool use. LangGraph adds stateful multi-agen...
View ToolPrivate local AI chatbot by Nomic. 250K+ monthly users, 65K GitHub stars. LocalDocs feature lets you chat with your own...
View ToolGive your agents a filesystem that branches like git. Crash-safe by default.
View AppCatch broken SKILL.md files in CI before they hit your team.
View AppReplay every MCP tool call to find why your agent went sideways.
View AppFull GitHub CLI support for automated PR and issue workflows.
Claude CodeReusable markdown files with instructions and workflows.
Claude CodeConfigure Claude Code for maximum productivity -- CLAUDE.md, sub-agents, MCP servers, and autonomous workflows.
AI Agents
Mistral releases Leanstral 1.5, an Apache-2.0 licensed 119B parameter model (6B active) for Lean 4 theorem proving that...

The Godot Foundation has established a policy banning autonomous AI agent code and substantial AI-generated contribution...

Ngrok engineer Sam Rose ported 100,000 lines of Kubernetes to TypeScript, creating a browser-based cluster for education...

A new project proposes a graphical shell layer for SSH that turns remote servers into browsable desktops. The HN discuss...

Armin Ronacher's new essay explores the tension between letting AI agents loop autonomously and maintaining the engineer...

A developer used OpenAI Codex to build a fully open-source WYSIWYG editor for TikZ figures. The technical approach and r...

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.