Duplicated file with different case in git origin (bitbucket)

I am trying to rename files from foobar.php to FooBar.php which is quite a challenge in Git. So far I have found out that I had to set up the git config value of ignorecase to false (why it was set to true on Mac OS X, anyway?). I have managed to rename those files successfully in my local repository, but after I pushed it to BitBucket I've got FooBar.php as well as foobar.php there. How do I get rid of these duplicates? Thanks.


Solution 1:

Case-insensitive, case-preserving

The problem you likely have is that the default file system on a mac is case-insensitive but case preserving; it is not possible in that circumstance for file.php and File.php to exist at the same time - they are considered the same file.

This is easy to demonstrate:

$ cd /tmp
$ mkdir example
$ cd example/
$ git init
Initialized empty Git repository in /private/tmp/so/.git/ 
$ touch readme
$ git add readme 
$ git commit -m "adding readme"
[master (root-commit) 05fdf7d] adding readme
 0 files changed
 create mode 100644 readme
$ mv readme x
$ git status 
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#  deleted:    readme
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       x
no changes added to commit (use "git add" and/or "git commit -a")
$ mv x README
$ git status 
# On branch master
nothing to commit (working directory clean)
$ ls -l
total 0
-rw-r--r--  1 andy  wheel  0 Aug  1 19:38 README

In the above the file is now named README yet according to git the file readme exists and is unmodified.

Use two commits

So instead of renaming the file (which on a case-insensitive system is problematic) do it as two steps:

$ mv file.php /tmp
$ git rm file.php
$ git commit -m "deleting file"
$ git push

Make sure that the undesired file is gone from the repository. Then, move the file back to the right location and add it.

$ mv /tmp/file.php File.php
$ git add File.php
$ git commit -m "adding File"
$ git push   

Solution 2:

Applied to Directories

As I was struggling with this issue on a directory level (rather than on a file level), here is the recipe applied to a folder (this was on Windows, git v2.9.2).

  • Bitbucket would be showing two subfolders, say Foobar and FooBar, with different files/folders beneath them.
  • On the client core.ignorecase was set to true and both file trees where merged into one under a common root, say Foobar.
    • Don't set core.ignorecase to false just yet, as it will leave you suddenly with "untracked" files from the other path!
  • git mv Foobar Foobar.tmp - You will get a set of renamed files, but also a set of deleted files and their corresponding untracked ones from the other path.
  • git add . - Stage all the deleted/untracked files.
    • That worked ok for me. Although these appear as deletes/additions, the history of those files is not lost (magically).
  • git commit -m"syncing Foo[Bb]ar into temp. folder" - Commit the temp. folder.
  • git mv Foobar.tmp FooBar - Now rename from temp. to the desired name.
  • git commit -m"moving FooBar into place" - Commit the target name.
  • git push - Now Bitbucket should show a single subdirectory FooBar.
  • git config [--global] core.ignorecase false - Never stumble into that problem again.

Solution 3:

Clone/checkout into a case-sensitive file system (on Mac OS X you can just make a case-sensitive disk image to do so), and then git rm the file with the capitalization you don't want.

As to why ignorecase was set to true, the documentation says:

core.ignorecase
The default is false, except git-clone(1) or git-init(1) will probe and set core.ignorecase true if appropriate when the repository is created.

Since your Mac probably has a case-insensitive filesystem (it's the default), git will have noticed that and set the flag appropriately.