Mac 与 Windows 协同开发中的 Git 换行符问题
# 彻底解决 Mac 与 Windows 协同开发中的 Git 换行符问题
让跨平台代码同步从此告别烦人的
^M和全文件飘红
—— 本文方案针对 Windows 为主团队的 CRLF 统一策略
# 📌 问题现象
作为一名同时使用 macOS 和 Windows 的开发人员,你一定遇到过这样的场景:
- 在 Mac 上愉快地写完代码,push 到仓库;
- 换到 Windows 上
git pull,什么都没改,但git status却显示大量文件被修改; - 执行
git diff看到满屏的^M字符,或者整个文件被标记为“全部删除+全部新增”; - 代码审查时,PR 中夹杂着成百上千行无意义的空白变更,真正的逻辑改动被淹没。
这正是跨平台换行符(line ending)不一致导致的经典问题。
# 🔍 根本原因
| 操作系统 | 换行符 | 转义表示 |
|---|---|---|
| macOS / Linux | LF | \n |
| Windows | CRLF | \r\n |
Git 默认行为:
- 在 Windows 上检出代码时,可能自动将 LF 转换成 CRLF;
- 在 macOS/Linux 上检出时,保持 LF;
- 提交时,Git 又会根据
core.autocrlf配置决定是否转换。
当 Mac 用户提交的文件是 LF,Windows 用户拉取后被转成 CRLF,再改几个字符保存,就会产生大量无关换行符的 diff。
# 🎯 方案选择:根据团队主流系统决定
网上的大多数教程会推荐统一使用 LF,因为这是 Linux/macOS 以及云原生 CI/CD 环境的默认标准。但如果你的团队主力开发机是 Windows,强行要求所有人使用 LF 反而会带来很多不便:
- Windows 上很多老旧工具(甚至某些公司内部脚本)对 LF 支持不佳;
- 部分 Windows 程序员习惯 CRLF,强制 LF 会导致他们本地看到大量文件被“修改”;
- 切换成本高,需要一次性规范化整个仓库。
因此,最务实的做法是:以 Windows 为主,统一使用 CRLF。这样 Windows 同事无任何感知,Mac 同事只要做好配置,也能完美适配。
# ✅ 解决方案:使用 .gitattributes 强制 CRLF
与其要求每个团队成员手动设置 git config,不如在项目仓库中声明换行符规则。.gitattributes 文件会跟随代码一起版本控制,优先级最高,一劳永逸。
# 1️⃣ 创建 .gitattributes 文件(CRLF 版)
在项目根目录下新建 .gitattributes,写入以下内容(核心:* text=auto eol=crlf):
# 所有文本文件统一使用 CRLF(Windows 原生格式)
* text=auto eol=crlf
# 特殊脚本文件(如需在 Linux/macOS 运行,必须保持 LF)
# 如果你的项目没有这类脚本,可以不加
*.sh text eol=lf
*.bash text eol=lf
# Windows 批处理文件已经是 CRLF,保持即可
*.bat text eol=crlf
*.cmd text eol=crlf
# 二进制文件禁止任何转换
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
*.zip binary
*.tar binary
*.gz binary
*.mp4 binary
*.mp3 binary
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
解释:
* text=auto eol=crlf:所有文本文件,无论原始格式如何,在检入仓库时都会被规范化,检出到工作区时强制转换为 CRLF。- 对于
.sh等需要在 Linux/macOS 上执行的脚本,单独覆盖为lf,避免执行报错(如果你没有这类文件,可以忽略)。
# 2️⃣ 提交配置文件并规范化现有仓库
# 先把 .gitattributes 本身提交
git add .gitattributes
git commit -m "Add .gitattributes to enforce CRLF line endings"
# 关键步骤:强制 Git 按新规则重新处理所有文件
git add --renormalize .
# 提交这次规范化变更
git commit -m "Normalize all line endings to CRLF"
# 推送到远程仓库
git push
2
3
4
5
6
7
8
9
10
11
12
⚠️ 注意:git add --renormalize . 可能会修改大量文件(尤其是原本混用 LF 的文件)。建议在独立分支上操作,并通知团队成员。
# 3️⃣ Mac 同事的额外配置
对于使用 macOS 的开发者,需要让 Git 在提交时正确处理 CRLF 文件。运行以下命令:
git config --global core.autocrlf input
这条命令告诉 Git:在 macOS 上,检出时不转换(保持 CRLF 原样),但提交时自动将 CRLF 转换为 LF 存入仓库。配合 .gitattributes 的 eol=crlf,效果是:工作区始终是 CRLF,仓库内也是 CRLF(因为提交时从 CRLF 转成 CRLF,无变化)。
Windows 同事无需任何额外配置,core.autocrlf 设为 true 即可(通常 Git for Windows 安装时已默认设置)。
# 4️⃣ 团队成员同步
其他成员拉取这次提交后,也需要运行一次规范化命令:
git pull
git add --renormalize .
# 如果没有本地未提交的修改,也可以直接 git reset --hard HEAD
2
3
# 🧪 验证是否生效
- 查看某个文件的换行符类型(Linux/macOS):
cat -A src/main.js | head -1 # 输出行尾为 ^M$ 表示 CRLF,输出 $ 表示 LF1
2 - 在 VS Code 中:打开文件,右下角状态栏会显示
CRLF或LF。 - 检查 Git 对文件的属性解读:
git check-attr -a src/main.js # 预期输出: src/main.js: text: set # src/main.js: eol: crlf1
2
3
# 🩹 临时手段:在 git diff 中忽略换行符
有时候你只是想快速查看代码逻辑变化,不想看到铺天盖地的空白差异。Git 提供了几个非常有用的参数:
# 忽略所有空白字符(包括换行符、行尾空格等)
git diff -w
# 仅忽略行尾空白符(空格、Tab)
git diff --ignore-space-at-eol
# 忽略行尾回车符 CR(即忽略 ^M)
git diff --ignore-cr-at-eol
2
3
4
5
6
7
8
你也可以给它们设置别名:
git config --global alias.diffw "diff -w"
git config --global alias.diffcr "diff --ignore-cr-at-eol"
2
注意:这些命令只影响 diff 的显示结果,不解决根本问题。长期方案仍然要使用 .gitattributes。
# 📚 总结:Windows 主力团队的推荐配置
| 角色 | 必须配置 | 可选配置 |
|---|---|---|
| 项目仓库 | 添加 .gitattributes 并设置 * text=auto eol=crlf | — |
| Windows 开发者 | 确保 git config core.autocrlf 为 true(通常默认) | 无 |
| macOS 开发者 | git config --global core.autocrlf input | 编辑器设置默认换行符为 CRLF(如 VS Code 中 "files.eol": "\r\n") |
| Linux 开发者 | git config --global core.autocrlf input | 同上 |
# 为什么我们选择 CRLF 而不是 LF?
- 团队现状:90% 的开发机是 Windows,他们不希望改变已有的 CRLF 习惯。
- 工具兼容:部分公司内部脚本、老旧 IDE、命令行工具严格依赖 CRLF。
- 改动最小:统一为 CRLF 后,Windows 同事看到零变化,只需 Mac 同事做一次配置和仓库规范化。
只要团队不涉及大量在 Linux 服务器上直接编辑文件(通常通过 CI/CD 自动处理),CRLF 方案稳定可靠。
# 🚀 最佳实践建议
- 新项目:从一开始就放入
.gitattributes,避免混乱。 - 老项目:找一个合适的时间点(如版本发布后),单独提交一个“规范化换行符为 CRLF”的 commit,并在 PR 中说明。
- 文档化:在团队 README 中写明换行符规范,让新成员第一时间知晓。
从此,无论是 Mac、Windows 还是偶尔的 Linux 开发者,提交的代码换行符都将整齐划一为 CRLF,git diff 中再也看不到无意义的 ^M 符号。让开发者专注于真正的代码逻辑,而不是被格式差异浪费生命。
写在最后:换行符问题看似微小,却足以让跨平台团队每周浪费数小时。希望这篇博客能帮助你一次性解决这个痛点。如果觉得有用,欢迎分享给更多被这个问题困扰的朋友。