jww jww - 1 year ago 52
Git Question

Why does 'git mv' not move a file? How to make it act "normally"?

Please forgive my ignorance here... Here's the background: I created a TestScritps directory to organize test scripts. I moved three scripts from

<root dir>
<root dir>/TestScripts
. I moved one at a time and performed a local commit after each one. I then pushed all the changes.

I went to another machine and performed a pull:

$ cd cryptopp/
$ git pull
remote: Counting objects: 25, done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 25 (delta 11), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (25/25), done.
From https://github.com/weidai11/cryptopp
2ac9ea1..2a22a84 master -> origin/master
Updating 2ac9ea1..2a22a84
TestScripts/cryptest-android.sh | 44 +
TestScripts/cryptest-ios.sh | 40 +
TestScripts/cryptest.sh | 5729 +++++++++++++++++++++++++++++++++++++++
rijndael.cpp | 2 +-
setenv-android.sh | 85 +-
5 files changed, 5870 insertions(+), 30 deletions(-)
create mode 100755 TestScripts/cryptest-android.sh
create mode 100755 TestScripts/cryptest-ios.sh
create mode 100755 TestScripts/cryptest.sh

$ ls *.sh
cryptest-android.sh cryptest.sh setenv-android.sh setenv-ios.sh
cryptest-ios.sh rdrand-nasm.sh setenv-embedded.sh

Notice the files were only copied; they were not moved.

I checked the
man page
, but the errant behavior does not appear to be discussed.

I have two questions. Why does
git mv
only copy files, and not move them? How can I make
git mv
perform "normally"? Here, "normally" means what nearly every person who has used the command line expects - it moves the file from
<target location>
<destination location>

Here is the relevant command history.

994 rm -rf cryptopp/
995 git clone https://github.com/weidai11/cryptopp
996 cd cryptopp/
997 mkdir TestScripts
998 git mv cryptest.sh TestScripts/
999 ls *.sh
1000 git commit TestScripts/cryptest.sh -m "Organize test scripts (Issue 303)"
1001 ls *.sh
1002 git mv cryptest-ios.sh TestScripts/
1003 git commit TestScripts/cryptest-ios.sh -m "Organize test scripts (Issue 303)"
1004 ls *.sh
1005 git commit

Answer Source

From the summary shown in the output of git pull, I see that those files were not deleted.

When you did e.g.:

git commit TestScripts/cryptest.sh -m "Organize test scripts (Issue 303)"

While Git is usually good about tracking files moves, internally a move is recorded as deleting one file and creating a new identical one. You committed the new file, and not the file deletion from the original location, thus making it look like Git just copied the file.

In the future, it's generally a good idea to leave out the filename from the commit command:

git commit -m "Organize test scripts (Issue 303)"

You can do git status beforehand to see what will be committed, and modify as needed.

A full session might look like this:

$ git mv cryptest.sh TestScripts/
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        renamed:    cryptest.sh -> TestScripts/cryptest.sh

$ git commit -m "Organize test scripts (Issue 303)"
$ git status
On branch master
nothing to commit, working directory clean
$ ls cryptest.sh
ls: cannot access cryptest.sh: No such file or directory
$ ls TestScripts/cryptest.sh

To fix, do:

git rm cryptes*.sh
git commit

If you want to fix your history instead, you can do:

git rebase -i HEAD^3

and change the command for the relevant commits from pick to edit. At each stop, do:

git rm <file>
git commit --amend
git rebase --continue

Where <file> is the current original file.

Note that this will rewrite your history, so it may cause problems when moving between machines.

Note that it should not be necessary to delete and re-clone a Git repo, so if you run into trouble in the future, it's better to try to fix the root issue. (Search around or ask here if you need help!)