git rm: Removing Files from Tracking and the Working Directory
Deleting a file from a Git-tracked project involves more than just deleting it from your file system — Git also needs to be told to stop tracking it, or the deletion itself won't be recorded as part of your project's history. `git rm` handles both of these concerns together, and also supports a special mode for untracking a file while deliberately leaving it in place on disk.
Learning Objectives
- Remove a tracked file from both the working directory and Git's tracking using git rm.
- Stop tracking a file while keeping it on disk using git rm --cached.
- Understand why manually deleting a file with rm (outside Git) still requires a follow-up git add or git rm.
- Recognize git rm as the command used, in Lesson 13 of Module 1, to properly untrack an already-committed file added to .gitignore.
Key Terms to Know Before Learning git rm
- git rm: A command that removes a file from both the working directory (deleting it from disk) and stages that deletion for the next commit.
- git rm --cached: A variant that stages a file's removal from Git's tracking, but leaves the actual file untouched on disk.
- Staged deletion: A file removal that has been recorded in the staging area, ready to be permanently recorded as a deletion in the next commit.
- Manual deletion (outside Git): Deleting a file directly via the operating system or an rm command, which Git will detect as a 'deleted' modification that still needs to be staged.
How git rm Actually Works
The straightforward use of `git rm` removes a file entirely — both from your working directory (it's actually deleted from disk) and from Git's tracking, with that removal automatically staged for the next commit:
```
git rm old-script.js
git commit -m "chore: remove unused old-script.js"
```
After running `git rm old-script.js`, the file is immediately gone from your file system, and `git status` shows it as a staged deletion, ready to be committed. This is the appropriate command when you genuinely want a file gone from the project entirely, both now and represented as a deletion event in history.
Sometimes, though, you want the opposite: you want Git to **stop tracking** a file, but you want to **keep the actual file** on your local disk. This is exactly the scenario from Module 1's `.gitignore` lesson — for example, an `.env` file that was accidentally committed before being added to `.gitignore`. For this, use the `--cached` flag:
```
git rm --cached .env
git commit -m "chore: stop tracking .env file"
```
This removes `.env` from Git's tracking and stages that change, but the file itself remains completely untouched on disk. Combined with a matching `.gitignore` entry, this is the correct way to permanently stop version-controlling a file without losing its local content.
It's worth understanding what happens if you delete a tracked file the 'manual' way — using your operating system's file explorer, or a plain `rm` command outside of Git, rather than `git rm`. In that case, Git notices the file is now missing from your working directory and reports it under 'Changes not staged for commit' as `deleted: old-script.js`. The deletion isn't yet staged — you still need to run either `git add old-script.js` (which, for a missing file, stages the deletion) or `git rm old-script.js` (which will simply confirm and finalize the already-performed deletion) before committing. In practice, using `git rm` directly from the start is cleaner and less error-prone than deleting manually and remembering a separate staging step afterward.
Finally, `git rm -r <directory>` recursively removes an entire directory and its contents from both the working directory and tracking, useful for cleaning up an entire obsolete folder at once.
git rm: Visual Walkthrough
Draw two parallel command flows. LEFT: 'git rm old-script.js' → arrow to a box showing BOTH 'File deleted from disk' AND 'Deletion staged for next commit'. RIGHT: 'git rm --cached .env' → arrow to a box showing 'File REMAINS on disk' but 'Untracking staged for next commit'. Below both, add a small note box: 'Manual rm / delete (outside Git) → Git shows "deleted: <file>" as unstaged — still requires git add or git rm to finalize.'
git rm: Quick Reference Table
| Command | Removes from Disk? | Removes from Git Tracking? |
|---|---|---|
| git rm <file> | Yes | Yes (staged for next commit) |
| git rm --cached <file> | No — file stays on disk | Yes (staged for next commit) |
| Manual OS/rm deletion (no Git command) | Yes | Not yet — shown as unstaged 'deleted' until git add or git rm is run |
| git rm -r <directory> | Yes, entire directory | Yes, entire directory (staged) |
git rm: Command Syntax and Examples
# Remove a file entirely: delete from disk AND stop tracking
git rm old-script.js
git commit -m "chore: remove unused old-script.js"
# Stop tracking a file, but KEEP it on disk (e.g., an accidentally committed .env)
git rm --cached .env
echo ".env" >> .gitignore
git add .gitignore
git commit -m "chore: stop tracking .env and add to .gitignore"
# Remove an entire directory recursively
git rm -r old-assets/
# What happens if you delete a file manually (outside Git) instead:
rm legacy-notes.txt
git status
# Shows: deleted: legacy-notes.txt (unstaged — still needs git add or git rm)
git add legacy-notes.txt # stages the already-performed deletion
Breaking Down the git rm Example
The first block shows the standard full removal — `old-script.js` is deleted from disk and its removal is staged in one step, ready to commit. The second block demonstrates the `--cached` pattern for untracking a file (like `.env`) while explicitly keeping it locally, immediately paired with adding it to `.gitignore` so it can never be accidentally re-tracked. The final block illustrates what happens if a file is deleted the 'manual' way, outside of Git entirely — Git detects the missing file and reports it as an unstaged deletion, requiring an explicit `git add` (or `git rm`) afterward to actually stage and finalize that deletion before it can be committed.
How git rm Is Used on Real Engineering Teams
- Security incident response frequently involves git rm --cached on files containing accidentally committed secrets, paired with credential rotation and a matching .gitignore entry to prevent recurrence.
- Codebase cleanup efforts (removing deprecated modules or unused legacy scripts) commonly use git rm -r on entire obsolete directories as part of a dedicated 'chore: remove legacy X' commit.
- Onboarding documentation at many companies explicitly teaches new hires to use git rm --cached rather than simply deleting a file and adding a .gitignore rule afterward, since the latter alone does not stop tracking an already-committed file.
- Build and CI scripts sometimes programmatically run git rm --cached on generated files that were mistakenly committed in the past, as part of a one-time repository cleanup migration.
git rm Interview Questions and Answers
Q1. What is the difference between git rm and git rm --cached?
git rm removes a file from both the working directory (deleting it from disk) and from Git's tracking, staging that deletion for the next commit. git rm --cached only removes the file from Git's tracking, leaving the actual file untouched on disk — used when you want to stop version-controlling a file without losing its local copy.
Q2. If you delete a tracked file manually using your operating system instead of git rm, what happens?
Git detects that the file is missing from the working directory and reports it as an unstaged deletion under 'Changes not staged for commit'. You still need to run git add <file> or git rm <file> to stage that deletion before it can be committed — the manual deletion alone isn't automatically recorded in history.
Q3. How would you properly stop tracking an .env file that was accidentally committed, without deleting it from your machine?
Run git rm --cached .env to remove it from Git's tracking while keeping the file on disk, add .env to .gitignore to prevent it from being re-tracked, and commit both changes together.
git rm Quiz: Test Your Understanding
1. What does git rm --cached <file> do?
- Deletes the file from disk and from Git tracking
- Removes the file from Git's tracking but leaves it on disk
- Deletes the file from disk but keeps it tracked
- Renames the file
Answer: B. Removes the file from Git's tracking but leaves it on disk
Explanation: The --cached flag scopes the removal to Git's tracking (the staging area/index) only, explicitly leaving the actual file content untouched on the local file system.
2. If you delete a tracked file using your operating system's file explorer instead of git rm, how does Git report it?
- It doesn't report anything — the deletion is automatically committed
- As an unstaged 'deleted' change, requiring git add or git rm to stage it
- As a merge conflict
- Git restores the file automatically
Answer: B. As an unstaged 'deleted' change, requiring git add or git rm to stage it
Explanation: Git status detects the file is missing and reports it as an unstaged deletion, which still needs to be explicitly staged with git add or confirmed with git rm before it can be committed.
3. Which command removes an entire directory, both from disk and from Git tracking?
- git rm --cached <directory>
- git rm -r <directory>
- git clean -fd <directory>
- git restore <directory>
Answer: B. git rm -r <directory>
Explanation: The -r (recursive) flag allows git rm to operate on an entire directory and all its contents, removing them from both the working directory and Git's tracking.
git rm: Common Mistakes Beginners Make
- Deleting a file manually (outside Git) and forgetting that the deletion still needs to be staged with git add or git rm before it's part of a commit.
- Using plain git rm when the intent was actually to keep the file locally, accidentally deleting something that was still needed on disk.
- Forgetting --cached is needed to untrack a file without deleting it, and instead manually re-creating a deleted file after realizing the mistake.
- Adding a file to .gitignore without first running git rm --cached on it, not realizing the file remains tracked from its earlier commits.
git rm: Exam-Ready Quick Notes
- git rm <file>: deletes from disk AND untracks (staged deletion).
- git rm --cached <file>: untracks only, file remains on disk (staged).
- Manual OS-level deletion still requires git add or git rm afterward to stage the deletion.
- git rm -r <directory>: recursively removes an entire directory from disk and tracking.
git rm: Key Takeaways
- git rm is the correct way to both delete a file and record that deletion in Git's history in a single step.
- git rm --cached is essential for untracking a file (like an accidentally committed secret) while preserving its local copy.
- Manually deleting a tracked file outside Git still requires an explicit staging step before the deletion becomes part of history.
Frequently Asked Questions About git rm
Q1. What does git rm do?
It removes a specified file from both your working directory (deleting it from disk) and from Git's tracking, automatically staging that deletion so it's ready to be included in your next commit.
Q2. How do I stop Git from tracking a file without deleting it from my computer?
Use git rm --cached <file>. This removes the file from Git's tracking and stages that change, but leaves the actual file completely untouched on your local disk.
Q3. What happens if I delete a tracked file using my file explorer instead of git rm?
Git will notice the file is missing and show it as an unstaged 'deleted' change in git status. You'll still need to run git add <file> or git rm <file> afterward to properly stage that deletion before committing it.
Q4. How do I remove an entire folder from Git, not just one file?
Use git rm -r <directory>, which recursively removes the directory and everything inside it from both your working directory and Git's tracking.
Q5. Should I use git rm --cached before or after adding a file to .gitignore?
If the file was already committed before you added it to .gitignore, run git rm --cached <file> to properly untrack it. Adding it to .gitignore alone does not remove an already-tracked file from history — the two steps need to be done together.
Summary
`git rm` removes a file from both the working directory and Git's tracking in one step, automatically staging the deletion for the next commit. `git rm --cached <file>` instead removes only Git's tracking of the file, leaving it fully intact on disk — the correct approach for untracking something like an accidentally committed `.env` file while keeping its local copy. If a tracked file is deleted manually through the operating system rather than through Git, the deletion is detected but shown as unstaged, requiring an explicit `git add` or `git rm` afterward to record it. `git rm -r <directory>` extends this to recursively remove entire folders.