Git: How to change the case of filenames

Dang, didn’t realize capslock was on!

Different filesystems have different case sensitivity, for example:

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.

Fin

May you always be on the case,

—Adam


If your Django project’s long test runs bore you, I wrote a book that can help.


Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: