Git克隆后无改动却提示gradlew.bat已修改的异常问题排查
问题根因
这是Git行尾归一化规则和仓库已提交文件状态不匹配导致的伪修改,和文件内容、权限、元数据没有关系:
- 仓库里存的
gradlew.bat原始Git对象(blob)是CRLF换行格式,是当初还没配置.gitattributes行尾规则时提交进库的 - 后来仓库加了
.gitattributes规则,把gradlew.bat标记为需要做行尾归一化的文本文件:Git对标记为text的文件,存库时会统一把换行转成LF,检出到工作区时再根据当前系统转成对应换行格式 - 你在Linux环境下操作时,Git检出文件不会改动已经是CRLF格式的原始blob内容,所以工作区的
gradlew.bat和GitHub直接下载的源文件完全一致,哈希值完全匹配,你自然查不到内容差异 - 但Git检查文件状态时,会对工作区文件跑clean过滤器(也就是把工作区文件转成待存库的标准格式)重新算哈希:这一步CRLF会被转成LF,算出来的哈希和仓库里存的CRLF版本blob哈希对不上,Git就会一直判定文件被修改
- 不管是
git checkout还是git reset --hard,都只是把仓库里存的CRLF版本重新写回工作区,不会改动Git对象库里的原始blob,所以操作完问题还是存在。
你看到
git diff显示整文件替换但内容完全一样,是因为默认diff输出不会标注行尾的CR/LF差异,跑git diff --ignore-cr-at-eol就能看到没有任何实际内容变更。
验证方法
执行以下三条命令就能确认问题:
- 查看索引里存的
gradlew.batblob哈希:
git ls-files --stage gradlew.bat
- 计算工作区文件经过clean过滤器(即Git认为应该存库的版本)的哈希:
git hash-object gradlew.bat
- 计算工作区文件不经过任何过滤器的原始哈希:
git hash-object --no-filters gradlew.bat
你会看到第二条命令的输出和索引里的哈希不一致,第三条命令的输出和索引哈希完全匹配,和前面的根因逻辑完全对应。
修复方案
在仓库根目录执行下面的命令,对所有已跟踪文件重新做行尾归一化,提交生成的变更就能彻底解决问题:
git add --renormalize . git commit -m "Normalize line endings for all tracked files"
修复后再克隆仓库,就不会出现刚拉取完就显示文件修改的异常。
内容的提问来源于stack exchange,提问作者Danilo Pianini
相关产品推荐
相关产品推荐

