Rename and Move Tracked Files Safely with git mv
You will finish with a tracked file renamed or moved, the Git index updated, and a check that shows exactly what is ready to commit. The examples use Git 2.43.0 from the Ubuntu git-man package, version 1:2.43.0-1ubuntu7.3.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need an existing Git working tree and a clean enough checkout that you can identify this operation's changes. These commands do not need elevated privileges. Do not use sudo: changing ownership or running Git as root can create a second set of permissions and configuration problems.
1. Check the starting state
Enter the repository and inspect its status before choosing a source path. This prevents unrelated edits being mistaken for the result of the move:
$ cd /path/to/project
$ git status --short
An empty response means the checkout is clean. If Git prints changes, either record them clearly or stop and deal with them first. A move does not hide existing work, but a busy status makes the final review harder.
Checkpoint: identify a file that is tracked, and decide whether the destination is a new name or an existing directory. Check tracking without changing anything:
$ git ls-files --error-unmatch docs/old-name.txt
docs/old-name.txt
Replace every example path with a real path from your repository. Do not use a path copied from an untrusted message without checking what it resolves to.
2. Preview a single rename
Use --dry-run when you want Git to report the planned operation without moving anything:
$ git mv --dry-run docs/old-name.txt docs/new-name.txt
Checking rename of 'docs/old-name.txt' to 'docs/new-name.txt'
Renaming docs/old-name.txt to docs/new-name.txt
The first form of the command takes one source and one destination. The source must exist and be a file, directory or symlink. A dry run is a read-only checkpoint, but it is not a guarantee that a later command will succeed if another process changes the tree in between.
3. Perform the rename and inspect the index
Once the destination is correct, run the same operation without --dry-run. Add --verbose if you want Git to print the path it is moving:
$ git mv --verbose docs/old-name.txt docs/new-name.txt
Renaming docs/old-name.txt to docs/new-name.txt
$ git status --short
R docs/old-name.txt -> docs/new-name.txt
git mv updates the working tree and stages the move in the index when it succeeds. The R in the first status column means the rename is staged. Git may later describe a delete and an add instead if the file's contents changed substantially, but the history review still happens at commit time.
Verify the staged paths directly:
$ git diff --cached --name-status
R100 docs/old-name.txt docs/new-name.txt
The similarity score, such as R100, is Git's current comparison and can vary after edits. It is not a permanent property of the commit.
4. Move files into an existing directory
To move one or more sources into a directory, make the final argument an existing directory:
$ test -d archive && echo 'destination directory exists'
destination directory exists
$ git mv --verbose notes/todo.txt notes/ideas.txt archive/
Renaming notes/todo.txt to archive/todo.txt
Renaming notes/ideas.txt to archive/ideas.txt
The directory must already exist. Git uses each source's basename, so these commands target archive/todo.txt and archive/ideas.txt. If you meant to give a file a new name, use a full destination path rather than a directory path.
Checkpoint: confirm that the old paths are gone from the working tree and the new paths are staged:
$ git status --short
R notes/todo.txt -> archive/todo.txt
R notes/ideas.txt -> archive/ideas.txt
$ git diff --cached --stat
archive/ideas.txt | 0
archive/todo.txt | 0
2 files changed, 0 insertions(+), 0 deletions(-)
Your stat formatting may differ. Check the path mapping rather than relying on the number of lines.
5. Handle a destination conflict deliberately
By default, Git refuses a move that would overwrite an existing file. This is a useful safety boundary. Do not add --force until you have inspected the destination and saved anything it contains:
$ git mv docs/old-name.txt docs/new-name.txt
fatal: destination exists, source=docs/old-name.txt, destination=docs/new-name.txt
The exact diagnostic can vary. Compare the two files before deciding whether replacement is intended:
$ git diff --no-index -- docs/old-name.txt docs/new-name.txt
$ git log --oneline -- docs/new-name.txt
If overwriting is genuinely required, preserve the destination first, then use the explicit force option:
$ cp --preserve=all docs/new-name.txt /tmp/new-name.txt.before-git-mv
$ git mv --force docs/old-name.txt docs/new-name.txt
This changes the destination and is not an undo operation. Keep the temporary copy until the staged diff and the resulting checkout have been reviewed. To abandon the staged move before committing, use git restore --staged and then restore or remove the working-tree paths only after checking what would be lost. A safer recovery for an ordinary, non-forced rename is:
$ git mv docs/new-name.txt docs/old-name.txt
$ git status --short
If the destination already existed or contents were changed, stop and reconstruct the intended state from the backup or a known commit instead of guessing.
6. Skip errors only when batch processing needs it
-k tells Git to skip individual moves that would fail, such as a missing source or an overwrite without --force. It is useful for a reviewed batch where partial completion is acceptable:
$ git mv --verbose -k notes/one.txt notes/missing.txt archive/
Renaming notes/one.txt to archive/one.txt
$ git status --short
R notes/one.txt -> archive/one.txt
Do not use -k to make an uncertain script look successful. A zero or non-zero result does not replace checking which requested paths were actually staged. For a small, important change, run one move at a time and let the first error stop your shell workflow.
7. Commit only after reviewing the change
git mv stages the operation; it does not create a commit. Review both the summary and the staged content, then commit through your normal project process:
$ git diff --cached --summary
rename docs/old-name.txt => docs/new-name.txt (100%)
$ git diff --cached --check
$ git commit -m "Rename old documentation file"
There is no service restart or elevated action in this workflow. A commit can be undone later with your team's normal Git recovery process, but rewriting shared history is disruptive, so agree on that step before using reset or force-push.
Done means
- The source path was checked and the destination was chosen deliberately.
- A dry run was used when the path mapping was easy to misunderstand.
git status --shortandgit diff --cached --name-statusshow only the intended staged moves.- No existing destination was overwritten without inspection and a recoverable copy.
- The staged diff passes
git diff --cached --check. - The move is committed only after the path and content review is complete.