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