In Git, why does adding an already-tracked file to .gitignore have no effect?
answer
- Every path is tracked or untracked
- Ignore rules only filter one of those sets
- The index already has an entry
- Remove from the index, keep the file on disk
basics
~20 sGit ignore rules apply only to untracked paths. Once a file has an entry in the index, Git keeps reporting and committing its changes whatever .gitignore says. Untrack it with git rm --cached, then commit that removal.
solid answer
~50 sA `.gitignore` pattern filters only the **untracked** set: the paths Git would otherwise list as new in `git status` and pick up with `git add .`. A file that already has an index entry is tracked, so its modifications keep showing up and keep getting committed no matter which pattern matches it. To make the rule bite, drop the path from the index while leaving it on disk with `git rm --cached secrets.env` (add `-r` for a directory), then commit that deletion together with the `.gitignore` change. From that commit on, the path is untracked and the pattern applies. Two caveats worth saying out loud: the deletion is a real change in history, so when teammates pull, Git removes the file from their working tree too. And untracking only affects the tip, every earlier commit still holds the contents, which matters if the file was a credential.
code
bash · 4 linesecho '.env' >> .gitignore
git rm --cached .env
git commit -m "chore: stop tracking .env"
git status --shortgo deeper
Be ready to state the rule in one line: ignore patterns apply only to untracked paths, and name git rm --cached as the fix. This is a standard first-screen Git question.
Explain the index entry as the reason, and what the resulting commit does when others pull it: the file disappears from their working tree. Mention listing offenders with git ls-files --cached --ignored --exclude-standard.
Show the operational care: warn the team before landing the deletion of a file people maintain locally, ship a checked-in example file, and treat any secret that was ever committed as compromised regardless of the untracking.
Own the prevention side: repository templates with a sane .gitignore from day one, secrets kept out of the tree entirely rather than untracked after the fact, and a policy for generated artifacts so this class of cleanup stops recurring.
## Tracked versus untracked Git sorts every path in the working tree into one of two states. A path is **tracked** if it has an entry in the index, the staging file at `.git/index` that records what goes into the next commit. Everything else is **untracked**: files Git knows nothing about yet. Ignore rules exist to keep the second set quiet. Without them `git status` in a real project drowns in build output, editor scratch files and dependency directories. So Git consults the exclude mechanism at exactly one point: when it is deciding whether an untracked path deserves to be mentioned or swept up by a bulk `git add`. A tracked path never goes through that question at all, because Git already committed to following it. ## Why Git works that way The rule is not an oversight. If ignore patterns silently detached tracked files, adding one line to `.gitignore` could quietly stop recording changes to files that are already part of the project, and a later commit would look complete while dropping real edits. Making untracking an explicit, committed operation keeps history honest: the moment a file stops being part of the project is a commit you can see and blame. ## The fix Untracking is `git rm --cached <path>`. It removes the index entry and stages a deletion, but leaves the file on disk, which is the difference from plain `git rm`. For a directory add `-r`. Then commit that deletion alongside the `.gitignore` change so the two land together. A common bulk variant for a repo whose `.gitignore` was fixed late is `git rm -r --cached .` followed by `git add .` and a commit. That re-reads every path through the current ignore rules and stages the removal of everything now excluded. Review the resulting diff before committing, it is easy to untrack more than you meant to. ## What it does to your teammates The commit contains a real deletion. When colleagues pull it, Git deletes the file from their working tree, because that is what applying a deletion means. For build output nobody cares. For a `config.local` or an `.env` that people hand-maintain, that is data loss on their machine, so announce it, or ship a checked-in `.env.example` alongside the change. ## Finding the offenders To list paths that are tracked yet matched by current ignore rules, use `git ls-files --cached --ignored --exclude-standard`. That is the audit query for a repo where the rules and the index have drifted apart. `git status --ignored` is a different question: it shows the ignored files that are present but untracked. ## Two adjacent traps First, untracking is not history rewriting. If the file was a leaked key, every commit that contained it still contains it, and the credential must be treated as compromised and rotated regardless of what you do to the repository. Second, people reach for `git update-index --assume-unchanged` or `--skip-worktree` to hide local edits to a tracked file. Those flags are index bits, not ignore rules: they suppress the change locally, other clones are unaffected, and the bit is easy to forget and later blame for lost work. If the file genuinely does not belong in the repository, untrack it. If it does belong but needs per-machine values, template it instead.
- What is the difference between git rm --cached and git update-index --skip-worktree for a file you want Git to stop bothering you about?`git rm --cached` untracks the file for everyone, as a committed change. `--skip-worktree` sets a bit in your local index only: the file stays tracked, your edits are hidden from status and diff, nothing is shared, and the bit survives until you clear it with `--no-skip-worktree`. It is a local workaround that regularly causes confusion when changes silently fail to appear.
- Someone pulls your commit that untracks a config file and loses their local settings. How do you avoid that?Announce the change, and land a tracked template alongside it, for example `config.example.yml`, plus a README line telling people to copy it. Because the commit carries a genuine deletion, Git removes the file on checkout for everyone; the only protection is warning people first and giving them a way to regenerate the content.
An ignore list is the guest list at the door, not a rule about people already sitting inside. Once someone is seated, you have to walk them out.
saying these in an interview costs you the question
- Thinks .gitignore retroactively removes the file from history
- Says git rm --cached deletes the file from disk too
- Believes untracking a leaked secret makes it safe
- Suggests deleting .git and re-cloning as the fix
- Uses git add -f every time instead of untracking