Ignoring files beyond .gitignore
Local-only ignores, untracking already-tracked files, hiding local edits to tracked files, and a global ignore for OS junk — the four problems .gitignore alone doesn't solve.
On this page
.gitignore is the standard, and the right tool when the patterns belong to everyone on the project. But it leaves four real situations underserved: local-only files, files you’ve already committed and want to stop tracking, files you need to edit locally without committing, and OS junk you want hidden everywhere. Each has a distinct tool — and they’re routinely confused for one another.
The four problems, the four tools
| Axis | .gitignore alternatives | What it actually does |
|---|---|---|
| .git/info/exclude | Local-only ignore patterns. | Same syntax as .gitignore but not tracked. Local to your machine; teammates don't see it. |
| git rm --cached | Stop tracking an already-tracked file. | Removes from Git's index. Keeps the local file. Once committed and pushed, the file disappears from teammates' next checkout. |
| --skip-worktree | Hide local edits to a tracked file. | Tells Git to treat the file as unchanged. Survives most operations including pull. |
| core.excludesfile | Global ignore across every repo. | User-level .gitignore. Best for OS junk like .DS_Store, Thumbs.db, IDE caches. |
Problem 1: a file only you care about
You have a notes.md or a personal run-dev.sh you don’t want to share. Adding it to .gitignore would force the whole team to carry a pattern that means nothing to them.
Tool: .git/info/exclude — same syntax as .gitignore, but the file lives inside .git/ and is never tracked.
echo "notes.md" >> .git/info/exclude
echo "run-dev.sh" >> .git/info/exclude
This works only for files Git doesn’t already know about. If notes.md is already tracked, the pattern is ignored — Git follows the rule “once tracked, always tracked, until you say otherwise.” Skip to problem 2.
Problem 2: a file is tracked, and shouldn’t be
A .env, an appsettings.json, or a .vscode/ directory that someone committed by accident. You want it out of Git but not deleted from your disk.
git rm --cached .env # single file
git rm -r --cached .vscode # directory
--cached removes from the index only. Your working-copy .env is untouched. Then:
- Add the pattern to
.gitignore(or.git/info/excludeif it’s just for you). - Commit the deletion.
- Push.
Problem 3: tracked file you need to edit locally
A config.json is checked in with reasonable defaults. You need to override two values locally and never commit those overrides.
Tool: --skip-worktree. Git pretends the file hasn’t changed regardless of what you do to it.
git update-index --skip-worktree config.json
# Edit config.json freely; git status stays silent.
# Undo when you want to track changes again:
git update-index --no-skip-worktree config.json
# List all files you've hidden this way:
git ls-files -v | grep "^S"
Problem 4: junk that follows you everywhere
.DS_Store on macOS, Thumbs.db on Windows, .idea/ from JetBrains IDEs, .vscode/ from VS Code. You don’t want to add these to every project’s .gitignore — they’re about your environment, not the project.
Tool: a global ignore file, registered once via core.excludesfile.
git config --global core.excludesfile ~/.gitignore_global
cat >> ~/.gitignore_global <<'EOF'
.DS_Store
Thumbs.db
.idea/
*.swp
EOF
Every repository on your machine now respects these patterns automatically, without polluting any project’s tracked .gitignore.
Decision shortcut
-
Is the pattern useful to everyone on the team?
Yes —
.gitignore. This is the default; don’t reach for the alternatives unless you have a specific reason. -
Is the file already tracked?
Yes —
git rm --cached, then add to.gitignore, commit, and warn the team. No — proceed to step 3. -
Is the pattern about your machine or your workflow?
Your machine, across all projects — global
core.excludesfile. This project only, just for you —.git/info/exclude. -
Is it a tracked file you need to edit locally without committing?
--skip-worktree. Not.gitignore(won’t apply to tracked files) and not--assume-unchanged(too weak).
Anti-patterns
A PR that adds my-notes.md or paths under a personal directory to the shared .gitignore.
.gitignore is the first ignore tool everyone learns, and the only one for which the syntax is widely known.
.git/info/exclude does the exact same thing without inflicting your habits on the whole team. Keep .gitignore for patterns that genuinely apply to everyone working on the project.
Using git update-index --skip-worktree .env.production because the file got committed with real credentials and you don’t want to deal with it.
The author wanted git status to stop showing the file and assumed “hidden from Git” meant “not on the remote.” The credentials are already in the remote’s history.
Rotate the credentials immediately. Then use git filter-repo (or git-filter-branch for older Git) to scrub the file from history, force-push, and warn collaborators. --skip-worktree only hides your working-copy state from your status output — it does nothing to the remote.
Quick reference
# Local-only ignore
echo "pattern" >> .git/info/exclude
# Untrack but keep on disk
git rm --cached <file>
git rm -r --cached <dir>
# Hide local edits to a tracked file
git update-index --skip-worktree <file>
git update-index --no-skip-worktree <file>
git ls-files -v | grep "^S"
# Global ignore
git config --global core.excludesfile ~/.gitignore_global