问题现象
在 Windows 上编辑仓库中的文件并执行 git status 时,文件显示为已修改(M),但 git diff 输出完全为空。执行 git add 后再执行 git commit,报错 nothing to commit, working tree clean。
根因分析
Git 的三种行尾模式
触发条件
-
仓库中的文件以 LF 存储(这是 Git 的默认行为)
-
Windows 上的
core.autocrlf默认为true -
Git 检出文件时自动 LF → CRLF,提交时自动 CRLF → LF
-
当文件被编辑保存后,磁盘上的 CRLF 版本与索引中的 LF 版本被 Git 判定为"不同"
-
git status显示已修改,但git diff对比的是工作区 vs 索引的内容,而行尾差异在 diff 层被忽略,所以显示为空 -
git add时 Git 执行 CRLF → LF 转换,与索引版本一致 →nothing to commit
为什么会反复出现
每次通过 Trae 编辑规则文件后,编辑器都会以 CRLF 格式保存文件。Git 在工作区看到 CRLF,索引中是 LF,于是又标记为已修改——形成循环。
解决方案
创建 .gitattributes 文件
在仓库根目录创建 .gitattributes,显式声明行尾策略,覆盖 core.autocrlf 的默认行为:
* text=auto eol=lf
配置项含义
相对于默认行为的优势
关键步骤:关闭 core.autocrlf
.gitattributes + Windows 默认的 core.autocrlf=true 会产生配置冲突:
.gitattributes: * text=auto eol=lf → 要求所有文本文件使用 LF
core.autocrlf: true → 等效于 * text=auto + core.eol=crlf(强制 CRLF)
根据官方 Git 文档:"If the eol attribute is specified, its line endings are determined by core.autocrlf or core.eol."——当 eol 显式指定时,core.autocrlf 不应决定行尾。但实际上 autocrlf=true 仍会产生 "LF will be replaced by CRLF" 警告噪音。关闭它是消除冲突的合理操作。
结果是:每次 git diff 都会报 CRLF 将替换为 LF 的警告。永久修复:
git config core.autocrlf false
git add --renormalize .
core.autocrlf false 关掉本地的 CRLF→LF 自动转换,交给 .gitattributes 统一管理。.gitattributes 会随仓库分发,自动覆盖所有克隆者的行为。
完整修复流程
# 1. 确保仓库根目录有 .gitattributes(未创建则先创建)
# 2. 关闭本地的 autocrlf
git config core.autocrlf false
# 3. 重写索引中的行尾记录
git add --renormalize .
# 4. 确认零警告
git diff --shortstat
# 输出为空即修复完成