Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~15 min· topic 6 of 6

Topic 1.6

Renaming, Removing & Cleaning Files: git mv, git rm, git clean

In one line

git mv old new renames a file and stages the rename. git rm file deletes it and stages the deletion. git rm --cached file stops tracking a file but keeps it on disk, which is how you un-commit a file that should have been ignored. git clean deletes untracked files: always preview with -n first. Git doesn't store renames, it detects them by comparing content, so git log --follow traces a file's history across renames.

0/6 · 0%

Think of it like this

Reorganising a filing cabinet with an assistant who keeps the index. Moving a folder, shredding a page, or taking a page out of the index (but keeping it on your desk) are three different requests, and you have to tell the assistant which one you mean.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

git mv
Rename or move a tracked file and stage the change.
git rm
Remove a tracked file from disk and stage the removal.
git rm --cached
Remove a file from Git's tracking (the index) but leave it on disk.
git clean
Delete untracked files and folders from the working directory.
Rename detection
Git pairing a deleted file with a similar added file and showing it as a rename.
--follow
A git log option that keeps tracing a single file's history through renames.

Step by step

01Rename a file

The team decides src/cart.js should live in src/checkout/cart.js. Priya uses git mv, and status shows a clean rename. She commits the move alone, before any edits, so the history stays easy to follow.

terminal
$ mkdir -p src/checkout
git mv src/cart.js src/checkout/cart.js
git status --short
git commit -m "refactor: move cart into checkout/"
── expected output ──
R src/cart.js -> src/checkout/cart.js
[main 4e5f6a7] refactor: move cart into checkout/
1 file changed, 0 insertions(+), 0 deletions(-)
rename src/{ => checkout}/cart.js (100%)

02History across the rename

Plain git log on the new path stops at the move, as if the file was born there. --follow traces it back through the rename.

terminal
$ git log --oneline -- src/checkout/cart.js
git log --oneline --follow -- src/checkout/cart.js | tail -2
── expected output ──
4e5f6a7 refactor: move cart into checkout/
3a2b1c0 Add cart total
9f8e7d6 Create cart module

03Un-committing a file that should be ignored

Arjun's first commit included node_modules/ (40,000 files). He removes it from tracking without deleting it from disk, ignores it, and commits. It stays in old history, but future commits are clean.

terminal
$ git rm -r --cached --quiet node_modules
echo "node_modules/" >> .gitignore
git add .gitignore
git commit -m "chore: stop tracking node_modules"
ls node_modules | wc -l
── expected output ──
[main 5f6a7b8] chore: stop tracking node_modules
40213 files changed, 1 insertion(+), 3812440 deletions(-)
412
The folder is still on disk (412 packages), just no longer tracked.
Un-committing a file that should be ignoreddiagram
Rendering diagram…

04Cleaning build leftovers safely

After switching branches, Priya has stray build output and test reports. She previews first with -n, then deletes. Because -x would also remove ignored files like .env, she leaves it off.

terminal
$ git clean -nd
git clean -fd
── expected output ──
Would remove coverage/
Would remove dist/
Would remove tmp-report.html
Removing coverage/
Removing dist/
Removing tmp-report.html

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

The case-only rename that broke Linux builds

On her Mac, Priya renames menu.js to Menu.js in Finder and updates imports to ./Menu.js. Git shows nothing to commit for the rename.

terminal
$ git status --short
# CI on Linux:
npm run build
── what you'll see ──
M src/app.js
Error: Cannot find module './Menu.js' from 'src/app.js'

Myth vs fact

Myth

Git tracks renames.

Fact

It stores snapshots and detects renames afterwards by comparing content. That's why separate 'move' and 'edit' commits keep history readable.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    git clean -i gives an interactive menu to choose what to delete, and a .gitignore that matches your build output means git status stays readable and clean rarely needs -x.

Remember this

  1. 1

    git mv old.js new.js = rename on disk and stage it. Renaming in your file manager works too, followed by git add -A, because Git sees 'deleted old, added new' and pairs them up.

  2. 2

    Git detects renames by similarity (by default 50% of content the same). It doesn't record them. Rename *and* heavily edit in one commit, and Git may see a delete plus an unrelated new file. Rename in one commit, edit in the next.

  3. 3

    git rm file deletes the file and stages the deletion. git rm -r folder/ for folders.

  4. 4

    git rm --cached file = stop tracking, keep the file. Use it when a file like .env or node_modules/ was committed by mistake, then add it to .gitignore (Topic 1.4). If it contained a secret, see Topic 7.5.

  5. 5

    git clean deletes untracked files (never tracked ones): -n preview, -f force, -d include folders, -x also ignored files, -i interactive. These files aren't in Git, so they can't be recovered.

  6. 6

    Case-only renames (menu.js → Menu.js) are invisible on Windows and macOS by default, because those filesystems ignore case. Use git mv menu.js Menu.js so Git records it.

Explain it without notes

01

What's the difference between git rm and git rm --cached?

02

Why is git clean dangerous?

Practice

01

Rename a file with git mv and trace its history.

02

Stop tracking a committed log file without deleting it.

Trade-offs

  • ↔

    Separate move and edit commits keep history and blame clear but add a commit. git clean is a quick reset of build clutter but is permanent, so previews and good ignore rules matter.

Done when you can

  • I rename with git mv and commit moves separately.

  • I use git rm --cached for files that should be ignored.

  • I preview git clean with -n.