Git 大小写文件名冲突:Windows/macOS 改名后出现重复文件

在 Windows 和默认 macOS 文件系统(大小写不敏感)上改文件名大小写,Git 不会把它识别为 rename,而是把两个文件都保留在仓库里。

症状

执行 git pull 时出现:

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:

  'app/substation/controller/RiderAuditController.php'
  'app/substation/controller/RiderauditController.php'

原因

Git 内部是大小写敏感的,仓库里可以同时存在两个文件:

RiderAuditController.php
RiderauditController.php

但 Windows(NTFS)和 macOS(APFS 默认)认为它们是同一个文件,检出时只能保留一个,发生碰撞。

通常是有人在 Windows 上直接改了文件名大小写,Git 把旧文件和新文件都提交进去了。

确认仓库状态

在任意环境执行:

git ls-files | grep -i rideraudit

如果输出两行就说明仓库里确实存在两个文件:

app/substation/controller/RiderAuditController.php
app/substation/controller/RiderauditController.php

解决步骤(必须在 Linux 或 WSL2 上操作)

Windows/macOS 文件系统无法同时持有两个大小写不同的文件,操作只能在大小写敏感环境中完成。

方案一:Linux 服务器(推荐)

# SSH 到 Linux 服务器,确认两文件内容
diff app/substation/controller/RiderAuditController.php \
     app/substation/controller/RiderauditController.php

# 删除要废弃的文件(以删除大写版为例)
git rm app/substation/controller/RiderAuditController.php
git rm phalapi/src/rider/Model/RiderAudit.php

git commit -m "fix: remove duplicate case-sensitive files"
git push

方案二:WSL2(Windows 用户)

wsl
cd /mnt/c/projects/your-repo

git rm app/substation/controller/RiderAuditController.php
git commit -m "fix: remove duplicate case-sensitive files"
git push

push 之后,Windows/macOS 成员再 git pull 就不会再有冲突。

如果两个文件内容不同

先比较差异:

git diff --no-index \
    app/substation/controller/RiderAuditController.php \
    app/substation/controller/RiderauditController.php

查看哪个是最新版本再决定保留哪个。也可以用 git log 看提交历史:

git log --follow -- app/substation/controller/RiderAuditController.php
git log --follow -- app/substation/controller/RiderauditController.php

不推荐的绕过方式

  • macOS 创建大小写敏感卷(APFS Case-sensitive)
  • Windows 开启目录大小写敏感:fsutil file setCaseSensitiveInfo . enable

这两种方式只解决当前机器的问题,团队里其他 Windows/macOS 开发者继续会出问题。根本解决办法是清理远程仓库中的重复文件。

PHP 框架的额外风险

PHP 的 PSR-4 自动加载依赖文件名映射,如果保留了小写文件名但代码里用的是大写类名:

new Model_RiderAudit(); // 加载 RiderAudit.php

在 Linux 上 autoloader 找不到文件会报 Class not found

解决后建议全局搜索:

grep -R "RiderAudit\|Rideraudit" . --include="*.php"

确认所有引用和文件名一致。