Windows大小写不敏感导致的git冲突
来个好玩的,遇到过 git reset --hard
来回翻烧饼的事儿么?每reset一次,文件内容就更改一次,像鬼打墙一样。不信可以在Windows机器上clone下这个repo:
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'
然后就会发现刚拉的main
分支都不干净(橙色),而且git reset --hard
也失效了,仔细看才发现,每reset一次,会在大写
File.txt
和小写 file.txt
之间切换,神奇不?
在github上浏览 repo,会发现文件目录与本地的不同:
github上根目录有两个txt File.txt
和
file.txt
,两个文件夹 Folder
和
folder
,而本地只有一个file.txt
和一个
Folder
。而这也是 git reset --hard
失效的根本原因:
git是大小写敏感的,而Windows系统是大小写不敏感的。
所以这个问题只会出现在Windows上使用git的情况,Windows将
File.txt
和 file.txt
认为是同一文件,所以reset失效了。Linux/Mac与git一致,大小写敏感,所以不存在这样的问题。Folder
与 folder
也是同理,在Windows上这两个文件夹会被合并成同一个。
这个问题常常会在配置CICD时发现,本地是Windows环境,而部署编译的机器是Linux,会提示找不到文件,但在Windows环境中看文件明明是存在的……
解决方案
在Linux/Mac上把文件统一当然可以解决问题,但如果手边没有Linux怎么办?
git是大小写敏感的,因此可以通过 git mv
解决问题。
同名文件冲突
假设保留小写文件,将大写文件覆盖之:
(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
注意,直接在Windows中删除 File.txt
是不行的,两个文件都会被删除:
(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")
最后,commit change,分支上就干净了。
合并同名文件夹
可以通过两次 git mv
完成:
$ git mv Folder temp
$ git mv temp 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
其中fixconflicts分支已按本文解决了问题,供参考。
参考
# 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