KernelRanch
返回文章列表

同一文件为什么出现整页 diff:用 Git 属性锁定换行符

2026-11-13 #git#windows#shell

Windows 编辑器保存后,Git diff 突然显示整页变化。先用 git ls-files --eol 看索引和工作区的换行符,再查命中哪些属性。项目可以用 .gitattributes 约束常见文本类型,避免不同机器的全局设置给同一个路径不同的检出结果。

1. 本机复现

保存为 eol_lab.py,运行 python eol_lab.py,需能在 PATH 找到 Git。脚本只操作临时仓库,直接比较字节,避免终端或文本读取自动转换换行符。

from pathlib import Path
import subprocess
from tempfile import TemporaryDirectory

with TemporaryDirectory() as tmp:
    root = Path(tmp)

    def git(*args):
        return subprocess.run(
            ["git", *args], cwd=root, capture_output=True, check=True
        ).stdout

    git("init", "-q")
    git("config", "core.autocrlf", "false")
    script = root / "job.sh"
    batch = root / "job.cmd"
    script.write_bytes(b"echo ok\r\n")
    batch.write_bytes(b"echo ok\r\n")
    git("add", "job.sh", "job.cmd")
    assert git("show", ":job.sh") == b"echo ok\r\n"
    print("before: staged job.sh uses CRLF")

    (root / ".gitattributes").write_bytes(b"*.sh text eol=lf\n*.cmd text eol=crlf\n")
    git("add", ".gitattributes")
    git("add", "--renormalize", "job.sh", "job.cmd")
    for name in ("job.sh", "job.cmd"):
        assert git("show", ":" + name) == b"echo ok\n"

    script.unlink()
    batch.unlink()
    git("checkout-index", "--", "job.sh", "job.cmd")
    assert script.read_bytes() == b"echo ok\n"
    assert batch.read_bytes() == b"echo ok\r\n"
    print("after: both staged blobs use LF")
    print("checkout: job.sh=LF job.cmd=CRLF")

本地实测输出如下。

before: staged job.sh uses CRLF
after: both staged blobs use LF
checkout: job.sh=LF job.cmd=CRLF

2. 在已有项目中引入规则

text eol=crlf 的文本在索引中仍会以 LF 规范化,CRLF 用于检出。用 git check-attr text eol -- job.sh 查看属性的实际取值,再用 git ls-files --eol -- job.sh 对照 i/ 和 w/。如果看到 mixed,先查编辑器或生成脚本的输出。

在干净工作区里提交属性文件,并把 git add --renormalize -- <路径> 限定到准备迁移的已跟踪路径。查看 git diff --cached,把换行迁移单独评审,避免和业务改动混在一起。字节敏感的测试样本或二进制可用 -text 明确关闭换行转换,并用项目已有的校验方式确认字节。实验先移除两个临时样本,再从索引重新检出,分别验证暂存时的规范化和检出时的转换。

小结

把换行符当成项目级的文件属性管理。用 Git 自己的索引和检出结果验证迁移。

数据来源与检索时间

检索时间 2026-11-13。

来源URL对应内容
Git gitattributeshttps://git-scm.com/docs/gitattributes#_checking_out_and_checking_intext、eol、索引规范化和工作区换行
Git ls-fileshttps://git-scm.com/docs/git-ls-files#Documentation/git-ls-files.txt---eol显示索引和工作区的换行符

核验说明

  • Windows、Python 3.11.9、Git 2.54.0.windows.1 比较了两个样本的原始字节。项目现有文件或编辑器配置需要按路径另行核验。