GitMoving & Renaming (git mv)

Moving & Renaming (git mv)

git mv renames or moves a file and stages that change in one step. It is identical to running the OS-level move followed by two git add commands. You can also rename files with your editor or with plain mv — Git will figure out it was a rename when you stage the deletion and the addition.

Renaming a file

The simple form

Bash
git mv old-name.js new-name.js

git status
# renamed:    old-name.js -> new-name.js

git commit -m "Rename old-name.js to new-name.js"
Moving a file

Bash
git mv src/utils.js lib/utils.js
# moves the file into a different folder

git mv components/Header.js components/header/Header.js
# can rename and move at the same time
Moving a folder

Bash
git mv src/components src/views
# every file inside is moved as a rename

git status
# renamed: src/components/Header.js -> src/views/Header.js
# renamed: src/components/Footer.js -> src/views/Footer.js
git mv vs plain mv
  • git mv old new is exactly equivalent to: mv old new && git add new && git rm old.

  • If you prefer to rename in your file explorer or editor, that is fine — Git will detect the rename when you stage both the deletion and the addition.

  • Git does NOT track renames; it detects them when you ask. Rename detection is based on content similarity at commit time.

Rename detection

When you git status or git diff shows "renamed: A -> B", Git is inferring it from similarity. By default, files that are 50% similar are considered renamed. You can tune this:

Tweaking rename detection

Bash
git config --global diff.renames true              # default on modern Git
git diff -M70%   # require 70% similarity to call it a rename
git diff -B      # break apart and re-pair files even more aggressively
git log --follow path/to/file.js                   # follow through renames
git mv on a folder vs `git mv -r`

Unlike git rm, git mv does not need a -r flag. Pointing it at a directory moves the directory and everything inside it.

Forcing overwrite

When the target already exists

Bash
git mv -f old.js new.js
# Use only when you really want to overwrite new.js
Dry run

Bash
git mv -n old-name.js new-name.js
# Would move old-name.js -> new-name.js
# (no change made yet)
Following a file across renames

git log normally stops at a rename — --follow continues

Bash
git log --follow -p src/new-name.js
# shows history before AND after the rename
Common mistakes
  • Renaming a file outside Git and forgetting to stage both halvesgit status will then show one deletion and one untracked file. Run git add -A and Git will collapse them into a rename automatically.

  • Renaming with a typogit mv does not validate that the new path is sensible. Run git mv again to fix.

  • Renaming files on case-insensitive filesystems (macOS/Windows by default) — e.g., mv Foo.js foo.js may not register a rename. Use git mv explicitly: git mv Foo.js foo.js (Git is case-sensitive even when the FS is not).

Case-only renames on macOS / Windows

The two-step trick

Bash
git mv Foo.js TEMP_NAME.js
git mv TEMP_NAME.js foo.js
# Two moves are needed because the FS thinks Foo.js == foo.js
Or change the global config
On macOS you can also run git config --global core.ignorecase false to make Git case-sensitive — then case-only renames work in one step.
Don’t fear renames
  • A rename is not a delete + create from Git’s perspective — the file’s history follows it (with --follow).

  • git blame keeps working after a rename, telling you who wrote each line of the renamed file.

  • PR review tools show renames as one row rather than two, when they detect the rename.

Tip
Refactoring often involves renaming many files at once. Use your IDE’s rename refactoring (which preserves history when you commit), then commit the whole rename batch as a single focused commit — easy to review, easy to revert.