My team currently manages a git repo across multiple filesystems. Most of us use Windows, but some of us use Linux. Plus, we deploy our production code on a Linux server. This has led to multiple issues with the casing of filenames in our codebase (ie. importing Foo.js
when the file is actually foo.js
). Recently, I completed a cleanup on our project folder that consisted mostly of re-organizing our directories and renaming our directories/files to a common naming standard. A lot of those filename changes were changing the case of the file (e.g. foo.js
-> Foo.js
).
I was not fully aware of how git handles filenames differently on case-sensitive vs case-insensitive filesystems when I was making these changes and it resulted in a lot of weird errors. One thing that I came across when researching this was the ignorecase
value in .gitconfig
.
From the git-config documentation:
Internal variable which enables various workarounds to enable Git to work better on filesystems that are not case sensitive, like APFS, HFS+, FAT, NTFS, etc. For example, if a directory listing finds "makefile" when Git expects "Makefile", Git will assume it is really the same file, and continue to remember it as "Makefile".
…
Git relies on the proper configuration of this variable for your operating and file system. Modifying this value may result in unexpected behavior.
From what I'm able to understand from this, setting ignorecase = true
will make it so that if git detects the same file name but with different casing, it will change the name in the git index to match what is on the filesystem (i.e. if Windows has foo.js
and a git checkout/pull has Foo.js
, it will assume that foo.js
is correct and git will use that casing). My concern with that is what will happen if I push to remote and our deployment server picks up the change. It will then try to import Foo.js
which doesn't exist and error out.
However, by setting ignorecase = false
, then git should be able to detect that there is a difference in the filenames and properly replace the files. Is this correct, and should I have my team set this value to false because we work across different filesystems?
I've read posts where people say that you should absolutely do this, and some posts that say the exact opposite.
From what I'm able to understand from this, setting ignorecase = true will make it so that if git detects the same file name but with different casing, it will change the name in the git index to match what is on the filesystem (i.e. if Windows has
foo.js
and a git checkout/pull hasFoo.js
, it will assume thatfoo.js
is correct and git will use that casing).
No, this is backwards: the documentation states that if the index currently contains a Foo.js
, and the work-tree for whatever reason has a foo.js
, Git will assume that foo.js
is really Foo.js
and will put Foo.js
into the next commit. With core.ignorecase
set to false
, however, Git believes the work-tree entirely: git add .
would remove the uppercase name (and contents) and use the lowercase name foo.js
to install a new copy in the index based on the copy in the work-tree.
(To see what's in the index, use git ls-files --stage
, or leave out the --stage
to get just the file name. Note that this dumps the entire index contents! Add path arguments to select particular files, e.g., git ls-files "[Ff]oo.js"
, to look for just those files. The quotes are needed in Unix-like shells, such as bash, to keep the shell from interpreting the metacharacters [Ff]
here. The shell will remove the quotes. What to use in other Windows-specific command line interpreters, I'm not sure.)
In general, you should not alter core.ignorecase
. If you wish to rename a file, the most straightforward method is to use git mv
(to adjust both index and work-tree at the same time). If you want to change case only, you can git mv
twice:
git mv foo.js temporary-name
git mv temporary-name Foo.js
and now you have Foo.js
with an initial-capital in both index and work-tree. Some versions of Git may be able to deal with this without the intermediate temporary name, but all will do the right thing when you use the intermediate name.