Git reset --hard Not Working: File System Is Not Case Sensitive

git reset --hard not working: everytime you reset, the file is flipped between file.txt and File.txt, really weird...

It's not a joke, just clone this repo on Windows and you can reproduce it:

D:\$ git clone https://github.com/finisky/git-case-demo.git
Cloning into 'git-case-demo'...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 11 (delta 0), reused 8 (delta 0), pack-reused 0
Unpacking objects: 100% (11/11), 1.85 KiB | 126.00 KiB/s, done.
warning: the following paths have collided (e.g. case-sensitive paths
on a case-insensitive filesystem) and only one from the same
colliding group is in the working tree:

  'File.txt'
  'file.txt'

After clone the repo, you will find that the main branch is not clean. git reset --hard not working:

Browse the repo on GitHub, you will find that the folder structure are different with local:

GitHub has two files File.txt and file.txt, while local has only one file file.txt. GitHub has two folders Folder and folder, while local has only one folder Folder. That's why git reset --hard not working:

git is case-sensitive, while filesystem is not

So the problem occurs on Windows only. Windows regards File.txt and file.txt as the same file. Linux/Mac is case-sensitive as git, so the problem will never happen.

Similarly, Windows regards Folder and folder as the same one, so the files will be merged into one folder.

Typically, the issue will be found when you configure CICD pipeline. Your local development environment is Windows but the build agent is Linux. It's hard to debug as it reports that files are not found while they are in your Windows folder...

Solution

Apparently we can fix it in a case-sensitive environment such as Linux/Mac. The problem is, what if we don't have such environment (Windows only)?

The solution is to use git command git mv.

Fix Case-Insensitive Files

Assume we keep the lower case file and use the upper case file to overwrite it:

(fixconflicts -> origin)D:\git-case-demo$ git mv File.txt file.txt

(fixconflicts -> origin)D:\git-case-demo$ git status
On branch fixconflicts
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    File.txt
        modified:   file.txt

Note that directly deleting File.txt on Windows doesn't work, as both files will be deleted:

(fixconflicts -> origin)D:\git-case-demo$ git status
On branch fixconflicts
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    File.txt
        deleted:    file.txt

no changes added to commit (use "git add" and/or "git commit -a")

Finally, commit changes and the branch will be clean.

Merge Case-Insensitive Folders

Merge the two folders by two git mv:

$ git mv Folder temp
$ git mv temp folder

The idea is rename it to a different folder temp first, and then merge temp with folder:

(fixconflicts -> origin)D:\git-case-demo$ git mv Folder temp

(fixconflicts -> origin)D:\git-case-demo$ git status
On branch fixconflicts
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    Folder/file2.txt -> temp/file2.txt

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    folder/file1.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        temp/file1.txt


(fixconflicts -> origin)D:\git-case-demo$ git mv temp folder

(fixconflicts -> origin)D:\git-case-demo$ git status
On branch fixconflicts
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    Folder/file2.txt -> folder/file2.txt

Demo

Demo Repo: https://github.com/finisky/git-case-demo

FYI, the fixconflicts branch resolves all issues according to this article.

Reference

# Git is case-sensitive and your filesystem may not be - Weird folder merging on Windows

# Git on Windows: "merging" 2 directories with the same name but different case

# Git case sensitivity