skip to content

In Git, what does git rm --cached do, and when do you need it?

level: middleimportance: should knowfreq 55%

answer

  1. one tree loses the file, one keeps it
  2. the file survives on disk
  3. the next commit still records a deletion
  4. history keeps every earlier snapshot

basics

~20 s

git rm --cached removes a path from the index but leaves the file on disk. The next commit records the deletion, so the file becomes untracked locally while everyone who pulls that commit loses their copy on disk.

solid answer

~50 s

`git rm --cached <path>` deletes the index entry only; the file stays in your working tree and immediately shows up as untracked (or is hidden entirely if an ignore rule already covers it). Plain `git rm` removes the path from both the index and the disk. The usual reason to reach for it is a file that was committed by mistake — a local `.env`, an IDE folder, a build artefact. You untrack it, add a matching ignore rule, and commit both together. Two caveats matter. First, the commit you create *is* a deletion, so when a colleague pulls it, Git removes the file from their working tree — which is painful if it held their local settings. Second, untracking changes nothing about history: every earlier commit still contains the blob, so a leaked secret must be rotated regardless of what you do to the current tree.

code

console · 8 lines
console
$ echo ".env" >> .gitignore
$ git rm --cached .env
rm '.env'
$ git status --short
A  .gitignore
D  .env
$ ls .env
.env

go deeper

for a junior

Remember the one-line difference: git rm deletes from index and disk, git rm --cached deletes from the index only, so the file stays but becomes untracked.

for a middle

Explain it as an index-only move on the three-trees diagram and walk through the standard untrack-plus-ignore-rule change, including why the ignore rule belongs in the same commit.

for a senior

Demonstrate the operational judgment: warn the team before landing a deletion that will wipe their local config, ship a template file, and separate the mechanical git rm -r --cached . commit from feature work.

for a principal

Own the incident framing — untracking is cleanup, not remediation. Drive credential rotation, scan the pushed history, and decide deliberately whether a rewrite is worth the disruption it causes.

## What the flag actually changes `git rm` normally does two things at once: it removes the path's entry from the index and it unlinks the file from the working tree. `--cached` keeps the first half and skips the second. Placed on the three-trees diagram, it is an index-only operation — HEAD still has the file, the working tree still has the file, and the index no longer does. `git status` therefore shows a staged deletion, and once you commit, the working-tree copy becomes an untracked file. Safety behaviour is worth knowing: `git rm` refuses to proceed when the working-tree copy differs from what is recorded, so you cannot lose unsaved content by accident, and `-f` overrides that check. `-r` is required to recurse into a directory, and `--ignore-unmatch` makes the command exit zero when the path matches nothing, which is handy inside scripts. ## The canonical use case Someone commits a file that never belonged in the repository. The fix is a single small change containing three things: an ignore rule for the path, `git rm --cached` on it, and a commit that carries both. Do the ignore rule too late and the file simply reappears as untracked noise for everyone; do the removal without the ignore rule and the next careless `git add -A` re-adds it. The recursive variant `git rm -r --cached .` untracks *everything* without touching the disk. Following it with `git add .` re-adds only what current ignore rules permit, which is the standard way to make a newly written or corrected ignore file take effect on already-tracked paths. It produces one large mechanical commit, so it is worth doing on its own rather than mixed into feature work. ## The two things it does not do **It does not spare your colleagues.** The commit records a deletion of that path. When they pull, Git applies that deletion to their working tree, and the file disappears from their machine even though it survived on yours. If the file held per-developer configuration, tell the team before landing it, and ship a checked-in template file alongside the ignore rule so people can recreate their local copy. **It does not remove anything from history.** Git stores snapshots; every commit that contained the file still contains it, and the blob remains reachable through those commits, so garbage collection will never drop it. A credential that was pushed is compromised the moment it was pushed. Rotate the credential first; deciding whether to rewrite history is a separate, much heavier conversation. ## Neighbouring index-only operations `git mv old new` is the mirror image: it renames the file on disk and updates the index in one step, equivalent to `mv` followed by `git rm` on the old path and `git add` on the new one. Git does not store renames — a commit is a snapshot, so a rename is simply one path gone and another arrived. What `git mv` buys you is that the index is updated for you; the arrow you later see in `git status` or `git log --follow` comes from diff-time similarity detection, not from anything the command recorded. A related distinction candidates blur: untracking with `git rm --cached` is a real, shareable change to the repository's contents, while marking a file with `git update-index --assume-unchanged` or `--skip-worktree` is a purely local index flag that keeps the file tracked. If the file should not be in the repository, untrack it.

  • You commit the removal of a tracked .env file with git rm --cached. What happens on a colleague's machine when they pull?
    Git applies the recorded deletion, so their working-tree copy of `.env` is removed — including the local values they had in it. Warn the team, and land a checked-in template file plus the ignore rule in the same change so everyone can recreate their local copy quickly.
  • How does git mv differ from renaming the file with mv?
    `git mv` renames on disk and updates the index in one step, so the change is already staged; plain `mv` leaves Git seeing a deletion plus an untracked file until you stage both. Neither records a rename — commits are snapshots, and the rename arrow you see later comes from diff-time similarity detection.
  • Does untracking a leaked API key with git rm --cached make the repository safe?
    No. Every earlier commit still contains the blob and keeps it reachable, so garbage collection will not drop it and anyone with a clone or the push history still has the value. Treat the credential as compromised and rotate it; changing history is a separate decision with its own cost.

saying these in an interview costs you the question

  • Says it deletes the file from disk as well
  • Claims it purges the secret from history
  • Forgets to add the ignore rule in the same commit
  • Expects teammates to keep their copy after pulling
  • Confuses it with the assume-unchanged index flag

context