Case sensitive directory/file names in git
The Context
I was asked for help with someone’s failing tests in their CI. The error they were getting was a
no such file or directory
error on the line of an import. They had recently done a refactor which updated a filename from
button.tsx
to Button.tsx
and updated the corresponding imports from import { Button } from './button.tsx';
to import { Button } from './Button.tsx';
.On a local environment, the tests were passing and Git was showing everything was up-to-date with the main branch.
The Problem
Filesystems in UNIX-like systems are usually case-sensitive, meaning you can have both
James.txt
and JAMES.txt
, or a directory called ./james
and ./JAMES
in the same directory. MacOS doesn’t work like this - it’s case-insensitive which means you can get something like this:
$ touch file $ ls file $ touch FILE $ ls file # 'FILE' is the same as 'file' so nothing new is created
By default, Git ignores the case of directories and files it tracks →
DIRECTORY/FILE.txt
is the same as directory/file.txt
. So when you make a change of button.tsx
→ Button.tsx
git tracks this as the same file and doesn’t track a change, leading to differently named files locally and remotely.From the git config docs:
core.ignoreCase
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".
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.
Git relies on the proper configuration of this variable for your operating and file system. Modifying this value may result in unexpected behavior.
Solutions
This StackOverflow thread has some discussion on the matter.
Update the global config
You could update the default behaviour of Git to ignore cases, however this is not recommended as it can lead to duplicate files committed to your repo or incorrect conflicts happening later on down the line.
git config --global core.ignorecase false
The setting of
core.ignoreCase
should match the case-sensitivity of your local file system as it tells Git how to interact with your filesystem. If you are using MacOS or Windows (both case insensitive) ignoreCase
should be true
(false
for Unix).Run
git config --list
to see all you current config (or git config --global --list
to see your global config).Use git mv
If it’s just a file rename, you can use
git mv
to rename it in the filesystem and the Git refs:git mv -f file FILE # -f required if file already exists
Some people comment that moving via a temporary file (with a completely different name such as
file.temp
) is required.Ignore case sensitivity for one commit
git -c "core.ignorecase=false" add .
Here you need to ensure that the original file (with the old case) is removed from git history using
git rm
.