加载失败
这里讨论的是 Git 的邮件式补丁工作流:`git format-patch(生成可通过邮件发送的补丁)` 和 `git-am(把邮件式补丁应用到仓库)` 会根据正文里的 `---`、`diff -`、`Index:` 等标记判断补丁从哪里开始。问题在于,如果提交消息里意外出现未缩进的 `diff`,`git-am` 可能把它当成真正的补丁内容,连 GitHub 生成的“补丁”里那些仿 Email headers 也会让格式更迷惑。这个行为和老牌 Unix `patch(1)` 工具的历史兼容性有关,因为它一直偏向人类可读和宽松解析,而不是强 schema。评论里还提到,如果只是想在提交里保留额外说明,更合适的做法可能是用 `---` 故意截断,或者把补充信息放到 Git notes(Git 的附加注释)里。
有人批评 Unix 风格工具各自维护一套几乎没文档的文件格式,patch 之所以一直存在,只是因为它够老、够通用、而且人类可读。也有人反驳说,若把补丁改成 XML 或 JSON 这类严格 schema,确实能减少歧义,但会丢掉 patch 作为“可直接阅读文本”的核心价值。评论里还提到 patch 早于 SGML,说明这种格式问题本身就是历史遗留,而不是单一工具的偶发失误。
讨论重点在于 git-am(Git 中用于应用邮件式补丁的命令)会用 `---`、`diff -`、`Index:` 之类的行来判断正文哪一段开始是 patch。于是,只要提交消息里出现未缩进的 diff-like 文本,就可能被当成真正的补丁去应用,形成“假 diff 被误认”的现象。有人指出 GitHub 生成的补丁还夹着假 Email headers,让格式看起来像在假装自己是邮件,但实际上又没有把边界说清楚。
一些人认为,在提交消息里放 `---` 并不是 bug,而是邮件补丁工作流里一种有意的截断方式:分隔线之后的内容不会被 git-am 应用,从而允许作者保留额外说明。这样做的代价是放弃一部分 round-tripping,也就是从补丁恢复完整原文的能力。有人建议更好的替代方案是把补充信息放到 Git notes 里,或者至少把多余内容缩进,避免被误解析。
另一条线索是:即便补丁解析规则再严格,也不能把“应用来自不可信来源的 patch”变成安全操作。评论者强调,真正危险的不是这次的假 diff,而是任何能被提交到命令行工具里的恶意输入;只要源头不可信,格式歧义只是额外的混淆,不是根本安全边界。有人还拿 `curl | tee -a /etc/passwd` 之类的例子说明,很多 Unix 管道工具本来就不是为处理恶意输入设计的。
patch(1): 经典 Unix 补丁应用工具,按 diff 内容修改文件。
git-am(1): Git 用来从邮件式补丁中创建提交的命令。
git format-patch(1): Git 生成可通过邮件发送的补丁文件的命令。
Git notes: 附着在 commit 上的独立注释,不会改动提交本身。
DWIM: Do What I Mean,表示工具按“你大概想要的”方式宽松处理输入。