git忽略大小写的问题,以及远程仓库同时存在大小写不同的文件的解决方案

Posted by abining on December 19, 2024

写在前面

在项目开发的时候,一个99%的人都会遇到的问题:就是git作为版本控制工具。 文件名、文件大小写的问题。 因为我对git的理解不够深入导致花费了不少时间来排查,同时也体会到好的规范比好的技术其实更重要。

搭建环境

  1. 新建gitee仓库 image
  2. 执行创建git仓库的命令 image-1

搭建测试案例

  1. 新建一个文件夹testfolder,作为测试文件夹,并且里面有一个innertestfile.txt文件,里面有内容,作为测试文件
  2. 新建一个文件testfile.txt,并且添加内容,作为测试文件 查看git status, image-2
  1. 将testfile.txt添加到git仓库中 执行 add . 命令,将testfile.txt添加到git仓库中 执行 commit -m "add testfile.txt" 命令,将testfile.txt提交到git仓库中 此时远程仓库的情况: image-5

问题复现

  1. 现在修改testfile.txt文件,将testfile.txt修改为Testfile.txt,然后执行git status命令,发现git没有检测到文件的变化,因为git默认忽略大小写,所以git认为Testfile.txt和testfile.txt是同一个文件,所以没有检测到变化。

image-3

  1. 现在在更改了文件名的情况下,修改文件的内容。

image-4

  1. 然后提交,发现提交成功,但是远程仓库的文件名没有变化,还是testfile.txt,而本地仓库的文件名已经变成了Testfile.txt。

image-6

  1. 如果执行 git config core.ignorecase false,设置Git的规则为区分大小写(大小写敏感),此时执行 git status,显示有一个新的文件Testfile.txt

image-7

  1. 把这个新增的文件提交到远程仓库,执行 git add .,然后执行 git commit -m "add Testfile.txt",然后执行 git push,发现远程存在两个文件,一个是testfile.txt,一个是Testfile.txt。

image-8

  1. 此时如果同事现在拉取这个仓库,因为操作系统(mac和windows)是不支持文件名大小写区分的,所以他会发现,远程仓库有两个文件,一个是testfile.txt,一个是Testfile.txt,他会很懵逼,不知道该用哪个文件,所以这里我的mac系统会选择删除Testfile.txt,保留testfile.txt。

image-9

  1. 但是如果是linux操作系统,就会保留着两个文件,如下:

image-10

这里就遇到了两个问题:

  1. git 在团队开发中的规范问题,如果团队中有人修改了文件名的大小写,应该如何正确修改。
  2. git远程仓库的两个文件,在同事下次拉取仓库的时候,会报警(warn),存在文件命名的冲突,并且会只保存两个仅大小写不同的文件或者目录中的其中一个;所以需要删除远程仓库中不需要的文件。(这个问题本来可以在修改文件名的时候就解决,但是因为之前没有意识到,所以导致这个问题)

解决方法

对于本地的文件需要修改文件名的大小写

  1. 推荐执行 git config core.ignorecase false命令,将git的忽略大小写功能禁用。
  2. 对于需要修改文件名的大小写的情况,例如下面的案例中执行 git mv testfolder/innertestfile.txt testfolder/Innertestfile.txt,将文件名的大小写修改正确,这里把testfolder目录下的innertestfile.txt修改为Innertestfile.txt。
  3. 这时候,执行 git status命令,发现git已经检测到文件的变化,是一个renamed的变化,并且存入了暂存区。

image-11

  1. 这时候 git push,发现远程仓库的文件名已经变成了Innertestfile.txt,而不是innertestfile.txt。

image-12

对于本地的文件需要修改目录名的大小写

这里把根目录下的testfolder目录改成了Testfolder目录,和修改文件名的大小写有点区别。

1
2
3
4
5
6
7
8
# 将本地的 test 目录删掉,并生成一个新的目录 tempfolder
$ git mv testfolder tempfolder

# 将 tempfolder 目录改成 Testfolder 目录。此时,项目中只会存在 Testfolder 目录,不会存在 testfolder 目录。目标达成。
$ git mv tempfolder Testfolder

# 对于目录中存在目录的情况,可以使用-f参数
$ git mv -f testfolder tempfolder

执行 git status命令,发现在暂存区有reanmed类型的修改,然后直接push到远程,就可以了。

image-13

对于远程已经有了大小写不同的文件,如何解决

  1. 直接在文件夹中重命名文件或者文件夹名字为预期的名字,并且删除对非预期文件的跟踪,然后提交到远程仓库。例如这里需要删除远程仓库的A和a文件中的a文件。
  2. 使用 git ls-files命令查看所有已经被 Git 跟踪的文件;应该可以看到A和a文件都被跟踪了。
  3. 使用 git rm a命令,将文件a的跟踪从 Git 仓库中删除。
    1. 执行完这个命令后可能会删除本地的A文件,这是你之前已经执行过 git rm a命令,所以本地已经没有a文件了,所以会删除A文件。
    2. 可以使用 git restore A命令,将A文件恢复到最近一次提交的状态。
  4. 紧接着commit,push后,远程仓库的a文件就删除了,同时两个仓库都是只有A文件。

对于目录:

  1. 执行 git rm -r a命令,将目录a的跟踪从 Git 仓库中删除。
  2. 紧接着commit,push后,远程仓库的a目录就删除了,同时两个仓库都是只有A目录。

最后

关于是否区分大小写的补充说明

我们知道:针对文件/文件夹,Windows系统Mac系统通常是不区分大小写的;Linux系统是区分大小写的; Git默认是不区分大小写的,也可以通过改配置项,改为区分大小写。

不分区大小写,也有它的好处,比如:文件夹/文件的路径,很多时候就代表了网站地址、页面url的路径。而网站地址也是不区分大小写的,这是很关键的原因之一。

是否需要开启git的忽略大小写功能的探讨

执行 git config --global core.ignorecase false,全局设置 大小写敏感。这样下次修改了文件的时候,就会有感知,开发者就能看到修改。

在开发中,开发者对修改的文件或者目录在git status中文件名大小写修改没有感知,是很危险的,所以推荐使用命令 git config core.ignorecase false修改配置。重要的是:如果需要修改文件或者文件夹的名称,在修改完了之后,记得得把原来的文件使用 git rm <原文件>命令删除掉。

撤销未暂存的更改的命令

如果您想撤销对 testfile.txt 的删除操作(这个文件还没有被暂存),您可以使用以下命令:

1
git restore testfile.txt

这个命令会将 testfile.txt 恢复到最后一次提交的状态,撤销您在工作目录中对它的删除。

查看所有跟踪的文件命令

您可以使用 git ls-files 命令来列出所有已经被 Git 跟踪的文件:

1
git ls-files

这个命令会列出仓库中所有当前被跟踪的文件。

git mv命令

  1. git mv 就相当于运行了下面三条命令:
1
2
3
$ mv README.md README
$ git rm README.md
$ git add README

总结

  1. 良好的开发规范,可以避免很多不必要的麻烦。
  2. 推荐在一个仓库修改配置 git config core.ignorecase false的值,这样,在这个仓库中,文件名的大小写是敏感的,可以避免修改文件大小写git监测不到的问题。
  3. 如果需要重命名一个文件或者目录的大小写,推荐使用 git mv <旧文件名> <新文件名>命令,而不是直接在操作系统提供的命令来删除文件;对于目录,可以加上 -r参数。(这句话推荐加入团队的开发规范中)

参考

代码仓库地址:

https://gitee.com/chouvel/git_test__config_ignorecase.git

参考:

解决 Git 不区分大小写导致的文件冲突问题

Git-基础-记录每次更新到仓库