Git: How to change the case of filenames

Different filesystems have different case sensitivity, for example:
- The Linux filesystem ext4 is case sensitive, by default. It allows both
Example.txt
andexample.txt
to co-exist. - macOS’ default APFS is case insensitive, by default. It interprets the filenames
Example.txt
andexample.txt
andeXaMpLe.TxT
as all referring to the same file.
When working on a case-insensitive filesystem, Git detects the case-insensitivity and stores this in the core.ignoreCase
option for the repo. With this option set to true
, Git doesn’t consider a file as renamed if it has changed case. This can make it a challenge to add and commit such a change when it’s actually necessary.
Let’s look at how tp re-case an individual file, a loop to re-case multiple files, and how to git add
case changes made with any tool.
Change one file at a time
To change one filename’s case, use git mv
:
$ git mv Mathematics.py mathematics.py
This command both changes the file in the filesystem and stages the change in Git:
$ git status
On branch main
Changes to be committed:
renamed: Mathematics.py -> mathematics.py
Great, job done.
You might have tried to use a standard mv
to re-case the file, but due to the core.ignoreCase
option, Git would not detect this change. You can follow up mv
with git mv
to stage the change in Git:
$ mv Mathematics.py mathematics.py
overwrite mathematics.py? (y/n [n]) y
$ git mv Mathematics.py mathematics.py
$ git status
On branch main
Changes to be committed:
renamed: Mathematics.py -> mathematics.py
Alrighty.
Change multiple files with a shell loop
To re-case multiple files, you can use a shell loop running git mv
on each file. You can use git ls-files
to list files matching a pattern, and tr
to translate a string’s case. For example, to lower-case all .py
files on bash/zsh:
$ for f in $(git ls-files -- '*.py'); do git mv -k $f $(tr '[:upper:]' '[:lower:]' <<< "$f"); done
$ git status
On branch main
Changes to be committed:
renamed: Mathematics.py -> mathematics.py
renamed: MONETARY.py -> monetary.py
Très utile.
Add changes made to multiple files
Using such a shell loop might not fit your use case, so you might use another tool to batch re-case files. If you do, you can add the changes by telling Git to stop tracking the files with git rm --cached
, then adding them back:
$ git rm -r --cached .
$ git add .
$ git status
On branch main
Changes to be committed:
renamed: Mathematics.py -> mathematics.py
renamed: MONETARY.py -> monetary.py
Aha!
The --cached option
to git rm
tells Git to stage the files for removal the files, but leave them on disk. After re-adding them, Git detects the files as renames, because they have the same content.
Beware though that git add .
will also pick up any new files you may not mean to commit.
Don’t change core.ignoreCase
Whilst researching for this post I saw several sources that recommended disabling core.ignoreCase
for a repo, or even globally. This will make Git to detect case changes on case-insensitive filesystems, but it’s unsafe, as the docs warn:
Git relies on the proper configuration of this variable for your operating and file system. Modifying this value may result in unexpected behavior.
So, yeah, best to leave the option alone.
If your Django project’s long test runs bore you, I wrote a book that can help.
One summary email a week, no spam, I pinky promise.
Related posts:
- Git: How to set up a global ignore file
- Git: How to alias “master” as “main”
- How to Run a Command on Many Files in Your Git Repository
Tags: git