Git 踩坑记录:文件显示 modified,却无法 commit

问题背景

在 Windows + VS Code + Git 的前端项目中,遇到一个非常反直觉的问题:

  • git status 明确显示文件被修改(modified
  • 但无论执行:
    git add <file>
    git commit
    git commit -a

    都提示:

    no changes added to commit
  • 文件始终无法进入暂存区

该问题没有任何报错,极具迷惑性。

常见误判方向

在排查过程中,以下方向全部不是原因

  • Git 未安装或损坏
  • VS Code Git 插件异常
  • 文件被 .gitignore 忽略
  • 使用了 assume-unchanged / skip-worktree
  • Git 操作顺序错误

根本原因分析

问题本质是 Windows 下 Git 的换行符处理机制导致的假变更。

具体机制如下:

  1. 编辑器(VS Code)保存文件为 CRLF
  2. Git 配置了 core.autocrlf.gitattributes
  3. git status 比较的是 工作区文件
  4. git add 前会执行 clean 过滤
  5. clean 后的内容与 index 中完全一致
  6. Git 判断为:“实际没有变化”

于是出现了以下矛盾现象:

操作 结果
git status 显示 modified
git diff 有内容
git add 不报错,但不生效
git diff --cached 无内容
git commit -a 无效

快速判断方式

git diff <file>          # 有输出
git diff --cached <file> # 无输出

如果符合上述特征,基本可以确定是换行符问题。

解决方案(推荐)

关闭自动换行符转换,并强制重新规范化仓库文件:

git config --global core.autocrlf false
git add --renormalize .
git commit -m "normalize line endings"

该方案会让 Git 的 index 与工作区重新对齐,问题即可消失。

单文件兜底方案

如果只想快速提交某一个文件:

git rm --cached <file>
git add <file>
git commit -m "update file"

长期预防方案

在项目根目录添加 .gitattributes

* text=auto eol=lf

并执行一次:

git add --renormalize .
git commit -m "chore: normalize line endings"

总结

这是一个只在 Windows 环境中高频出现、但极少被直观解释清楚的 Git 问题。

关键认知点只有一句话:

git status 看到的变化,并不等于 git add 认为的变化。

理解 Git 的 clean / smudge 与换行符处理机制,可以避免大量无意义的排查时间。