Git Mv | How To Use Git-Mv To Rename And Move Files
Table of Contents
- Rename and move files in Git
- What is git mv?
- How do I use git mv?
- Git mv vs mv
- Git mv options (-f, -k, -n, -v)
- Git mv Examples
- Can I git mv a directory?
- Git mv case sensitivity
- Next Steps
Rename and move files in Git
Developers using Git often find they need to rename or move files or directories in their software development projects. This can be achieved using the standard Unix
mv command, but Git offers a more efficient alternative
Although the concepts are quite simple, there is some nuance and a few edge-cases to be aware of. We recommend that you learn git mv to maximize Git understanding and collaboration, which can help you brand yourself as a strong asset to any team.
In this article we'll discuss:
- Renaming files in Git
- Moving files in Git
- The difference between
- Git mv options
- Git mv examples
- Using git mv on directories
- Git mv case sensitivity
We consider git mv to be an intermediate Git command, on-par with others such as
git tag, and other commands that are slightly more advanced than beginner Git commands such as
git add and
What is git mv?
According to the Git FAQ, "The effect [of git mv] is indistinguishable from removing the file and adding another with different name and the same content" (1).
This means git mv is equivalent to the following sequence of three commands:
- mv old_file.ext new_file.ext
- git add new_file.ext
- git rm old_file.ext
These series of steps uses the Unix/Linux
mv command to change the file name. Then it uses the git add command to stage the new version of the file and the git rm command to remove the file from Git's tracking.
So, the git mv command streamlines the process of renaming or moving files for us by inherently updating Git's index for our new paths.
How do I use git mv?
To move or rename a file using git mv, simply specify the existing and new paths of the file after the command:
git mv ./old_directory/old_file.ext ./new_directory/new_file.ext
In this case, we are both moving and renaming the file, and making Git aware of those changes.
Git mv vs mv
So, what’s the difference between running
git mv vs a simple
mv command? The answer lies in in the purpose of Git itself: to efficiently track changes.
Git mv automatically stages the moved file, so a simple git commit will suffice after your move or rename is complete.
Note, however, that if you make changes to a file prior to running git mv on it, these changes will not be staged until you run
git add. This is because git does a great job of only staging intended changes. In the world of Git, changes to code take precedent over the renaming of a file.
In other words, Git doesn't presume you’re ready to stage your code updates simply because you renamed a file.
Another difference worth noting is that the regular
mv command will overwrite a destination file of the same name without asking, whereas
git mv will refuse the action, and notify you that the destination file already exists. That is, of course, unless you tell Git to do otherwise by using the options included with the git mv command.
Git mv options (-f, -k, -n, -v)
git mv -f: This option is one way to resolve the issue of the destination file already existing. By using the
-f flag, we are telling Git to overwrite the destination with the source file we would like to move. Remember to use caution when using the -f option; if you overwrite a file only to find out later you need the contents, it could result in a time consuming search through Git's history.
git mv -k: This option will allow Git to simply skip any erroneous conditions resulting from a git mv call. Remember, the default behavior of Git is to throw an error if you attempt to move a file to a destination that already exist. With the
-k flag, rather than throwing an error or overwriting the destination, Git will simply skip over this action.
git mv -n: Shorthand for --dry-run, and will show you the output of the command in question without actually performing any of the changes.
git mv -v: Shorthand for --verbose, this command will report the names of the files in question as they are moved.
See the git mv docs for more details.
Git mv Examples
Let’s take a look at a few examples; consider the following directory tree in a Git repository, with a folder named
git-mv/ at the root, two files that Git knows about, and two empty subdirectories
git-mv/ | simplefile1.ext | simplefile2.ext | dir1/ | dir2/
Let's try out a simple rename command with git mv:
> git mv simplefile1.ext simplefile3.ext
This renames simplefile1.ext to simplefile3.ext, but let’s take a closer look:
> git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: simplefile1.ext -> simplefile3.ext
As we can see, Git has staged the rename for us, saving us the extra effort. Let’s try moving our newly renamed file into the
dir1/ directory, and take a look at how Git tracks that:
> git mv simplefile3.ext dir1/ > > git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: simplefile1.ext -> dir1/simplefile3.ext
Be careful using the git restore command to unstage the file, as specified in the [git status](/blog/git-status) output! This will unstage the file, but it won't undo the renaming or file move.
We can also run
git diff --staged to get some additional perspective:
> git diff --staged diff --git a/simplefile1.ext b/dir1/simplefile3.ext similarity index 100% rename from simplefile1.ext rename to dir1/simplefile3.ext
Wait a minute! What happened to our initial rename (before moving the file into
dir1/? Is Git’s tracking mechanism glitching out on us?
Quite the opposite - what Git is doing here is tracking the current state of the file, since the intermediate form was never committed. The
simplefile1.ext now exists in
dir1/ and is called
simplefile3.ext. There is no need to track the fact the actual file rename happened separately from the move (in fact it could have all been done in 1 step). The git diff algorithm shows differences relative to the current state of the changed file, (which combines the result of the two changes), along with keeping it staged and ready to commit. Pretty cool.
Can I git mv a directory?
Another obvious need arises when we want to move a directory into (or out of) another directory within our project. Git mv comes equipped to handle this with ease; let’s try moving our
dir1/ directory into
dir2/ and see what happens:
> git mv dir1/ dir2/ > > git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: dir1/simplefile3.ext -> dir2/dir1/simplefile3.ext
As git status reports,
dir1/ was moved into
dir2/ on the filesystem and git is aware of this change.
But what about in the case of nested files and directories - is git mv recursive? Let’s find out:
> mkdir dir3 > > git mv dir2/ dir3/ > > git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: dir1/simplefile3.ext -> dir3/dir2/dir1/simplefile3.ext
As you can see, our nested folders, along with their contents, were successfully moved. Git mv will move your directories recursively, without any extra flags or options.
Note that if the destination directory dir3/ in the previous example didn't exist yet, the source directory dir2/ would have been renamed instead of moved. But since we created dir3/ using the mkdir command, the whole directory tree under dir2/ was moved into dir3/.
Git mv case sensitivity
One more cool feature of Git's mv command is the ability to rename files with specific casing. For those of us who tend to stick with specific naming conventions such as camelCase, this can come in handy for cleaning up files in a project directory to suit your casing preference.
Let’s try changing simplefile2.ext to camel case and see what happens:
> git mv simplefile2.ext simpleFile2.ext > > git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: simplefile2.ext -> simpleFile2.ext
Nice! Our case change is locked and loaded and ready for a git commit. Compared with an
mv command, this is excellent. The
mv by itself not only lacks the ability to stage our changes, it’s also unwilling to entertain our casing quirks. The
git mv is certainly the way to go.
Git, like many other command line interfaces, comes with some pretty neat features. However, as with most tools, it’s important to take a finer look in order to understand the strengths of what you’re working with. The git mv feature works seamlessly with the git workflow, and now you can move files and rename files with confidence!
If you're interested in learning more about how Git works under the hood, check out our Baby Git Guidebook for Developers, which dives into Git's code in an accessible way. We wrote it for curious developers to learn how Git works at the code level. To do this we documented the first version of Git's code and discuss it in detail.
We hope you enjoyed this post! Feel free to shoot me an email at firstname.lastname@example.org with any questions or comments.
- Git FAQ https://git.wiki.kernel.org/index.php/Git_FAQ#Why_does_Git_not_.22track.22_renames.3F
Recommended product: Decoding Git Guidebook for Developers