Tuesday, August 23, 2011

git mv and case-insensitive file system

Many of you Java programmers have seem a problem with git or SVN: if you made a typo in class name, e.g.
test.java instead of Test.java, you cannot rename a file:


alf-imac:case alf$ echo "Test file" > test.java
alf-imac:case alf$ git add test.java
alf-imac:case alf$ git commit -m "Oh, what a stupid mistake"
[master (root-commit) 8ffb354] Oh, what a stupid mistake
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 test.java
alf-imac:case alf$ git mv test.java Test.java
fatal: destination exists, source=test.java, destination=Test.java


As you can see, git does not want to rename test.java to Test.java since there's no difference. When you're using
an IDE, the problem gets worse: you can end up changing the code and even committing it, just to find out a bit
later it's not running on your Linux server any more.


Anyway, how do we fix it? The trick is plain and simple, we use an intermediate name:



alf-imac:case alf$ git mv test.java test1.java
alf-imac:case alf$ git commit -m "Step 1"
[master c6f8021] Step 1
1 files changed, 0 insertions(+), 0 deletions(-)
rename test.java => test1.java (100%)
alf-imac:case alf$ git mv test1.java Test.java
alf-imac:case alf$ git commit -m "Step 2"
[master d7ca2ef] Step 2
1 files changed, 0 insertions(+), 0 deletions(-)
rename test1.java => Test.java (100%)


Unfortunately, it leaves us with an ugly history, so we need to adjust it:




alf-imac:case alf$ git log
commit d7ca2ef313d9b273baffcb6c15b3a96310659767
Author: Alexey Filippov <alf@*****>
Date: Tue Aug 23 12:02:18 2011 +0100


Step 2


commit c6f80218d69c5019db5f2b16fcf652e1a0445cb4
Author: Alexey Filippov <alf@*****>
Date: Tue Aug 23 12:01:49 2011 +0100


Step 1


commit 8ffb3542567057978cb7932fddaa38c2a2fbb59c
Author: Alexey Filippov <alf@*****>
Date: Tue Aug 23 11:55:21 2011 +0100


Oh, what a stupid mistake
alf-imac:case alf$ git rebase -i 8ffb3542567057978cb7932fddaa38c2a2fbb59c
[detached HEAD bb3f659] Renaming the file
1 files changed, 0 insertions(+), 0 deletions(-)
rename test.java => Test.java (100%)
Successfully rebased and updated refs/heads/master.

alf-imac:case alf$ git log
commit bb3f659989d43851e1600c93a922c59b8c7c64d3
Author: Alexey Filippov <alf@*****>
Date: Tue Aug 23 12:01:49 2011 +0100


Renaming the file


commit 8ffb3542567057978cb7932fddaa38c2a2fbb59c
Author: Alexey Filippov <alf@*****>
Date: Tue Aug 23 11:55:21 2011 +0100


Oh, what a stupid mistake

Obviously, the same effect could be achieved using --amend in the second commit.


PS. As I always suspected, the same approach is explained on StackOverflow in two lines. Silly me.

No comments: