Skip to content

fix(repo): enforce LF checkouts across platforms #291

Description

@yxr-2025

问题

仓库目前没有 .gitattributes 或其他仓库级换行策略,因此工作树中的换行符由开发者机器的 Git 配置决定。在 Windows 上,当 Git 配置为常见的 core.autocrlf=true 时,源码会从索引中的 LF 被检出为 CRLF。

在最新 main@865f66e 上已复现:

$ git config --show-origin --show-scope --get-all core.autocrlf
system  file:C:/Program Files/Git/etc/gitconfig  true

$ git ls-files --eol
323 files: i/lf w/crlf
0 files:   i/lf w/lf

这里 i/lf w/crlf 表示 Git 索引保存 LF,但工作树文件实际为 CRLF。由于 Git 在比较时会自动归一化,git status 仍然显示工作区干净,因此问题不容易被发现。

实际危害

这已经破坏了仓库的本地验证契约,而不只是代码风格差异:

$ bun run format:check
Checked 270 files
Found 270 errors
error: script "format:check" exited with code 1

Biome 对这些文件的建议改动基本都是移除行尾的 \r。因此在一个没有源码修改、且 git status 干净的最新主分支上,bun run check 仍会在格式检查阶段失败。

具体影响包括:

  • Windows 贡献者无法在干净 checkout 上可靠执行仓库要求的 bun run check
  • 运行自动格式化可能触发全仓库换行重写,掩盖真正的功能 diff 并增加 review 成本;
  • 同一 revision 在不同平台拥有不同的工作树字节,降低本地测试、文本处理和发布制品的可重复性;
  • Git 状态仍显示干净,使失败表面上看起来像 Biome 或源码格式问题,增加排查成本;
  • 每位 Windows 贡献者都需要知道并手工覆盖系统 Git 配置,项目本身没有提供 fail-closed 的规范。

这与 #69 中“用户输入包含 CRLF 时 fenced Markdown 的解析问题”不同。本 issue 关注的是仓库源码 checkout 策略以及由此导致的验证失败。

建议修复

在仓库根目录增加 .gitattributes,由仓库而不是开发者机器决定文本文件的工作树换行:

* text=auto eol=lf

如后续存在必须使用 CRLF 的 Windows 专用文件,可以再为具体扩展名单独声明;二进制文件继续由 text=auto 识别,必要时可增加显式 binary 规则。

同时可在贡献文档中提供当前工作树的一次性恢复步骤,例如在确认工作区干净后重新从索引检出文件。个人可以使用仓库级 core.autocrlf=false 作为本地覆盖,但个人配置不应代替仓库级策略。

修复收益

  • Windows、macOS 和 Linux checkout 获得一致的源码字节;
  • 干净 checkout 可以直接通过 bun run format:check,恢复 bun run check 作为可信验证入口;
  • 避免全仓库换行噪声,使提交和 review 聚焦真实行为变化;
  • 降低新贡献者的环境配置成本和隐蔽故障排查成本;
  • 提高文本测试、构建和 npm 发布输入的跨平台可重复性。

验收标准

  • 仓库根目录存在明确的 LF checkout 策略;
  • 在 Windows 且 core.autocrlf=true 的新 checkout 中,源码显示为 i/lf w/lf
  • 干净 checkout 上 bun run format:check 通过;
  • 应用换行策略后不产生源码内容层面的意外 diff;
  • bun run checkbun run test 通过。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions