I'd read that when renaming files in Git, you should commit any changes, perform your rename and then stage your renamed file. Git will recognise the file from the contents, rather than seeing it as a new untracked file, and keep the change history.
However, doing just this tonight I ended up reverting to git mv
.
> $ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
I renamed my stylesheet in Finder from iphone.css
to mobile.css
:
> $ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
# Changed but not updated:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: css/iphone.css
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# css/mobile.css
So Git now thinks I've deleted one CSS file, and added a new one. It is not what I want. Let’s undo the rename and let Git do the work.
> $ git reset HEAD .
Unstaged changes after reset:
M css/iphone.css
M index.html
I am back to where I began:
> $ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
Let's use git mv
instead:
> $ git mv css/iphone.css css/mobile.css
> $ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# renamed: css/iphone.css -> css/mobile.css
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: index.html
#
It looks like we're good. So why didn't Git recognise the rename the first time around when I used Finder?
For
git mv
the manual page saysSo, at first, you have to update the index on your own (by using
git add mobile.css
). Howevergit status
will still show two different files:You can get a different output by running
git commit --dry-run -a
, which results in what you expect:I can't tell you exactly why we see these differences between
git status
andgit commit --dry-run -a
, but here is a hint from Linus:A
dry-run
uses the real renaming mechanisms, while agit status
probably doesn't.