提交补丁:将你的代码合入内核的必备指南

对于希望向 Linux 内核提交更改的个人或公司来说,如果不熟悉“这套系统”,这一过程有时会令人望而生畏。本文汇集了一些建议,可以极大地增加你的更改被接受的机会。

本文档以相对简练的格式包含大量的建议。有关内核开发过程工作方式的详细信息,请参阅 内核开发过程指南。此外,请阅读 Linux 内核补丁提交核对清单 以获取提交代码前需要检查的项目列表。对于设备树绑定(Device Tree binding)补丁,请阅读 提交设备树(DT)绑定补丁

本文档假定你正在使用 git 来准备补丁。如果你不熟悉 git,建议你花时间学习如何使用它,这会使你作为内核开发者的生活以及日常工作变得轻松得多。

某些子系统和维护者树有关于其工作流和期望的附加信息,请参阅 子系统和维护者树特定的开发过程说明

获取当前的源码树

如果你手头没有包含当前内核源码的仓库,请使用 git 获取一个。你通常应该从主线仓库开始,可以通过以下方式获取

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

但是请注意,你可能不希望直接针对主线树进行开发。大多数子系统维护者维护自己的树,并希望看到基于这些树准备的补丁。请参阅 MAINTAINERS 文件中该子系统的 T: 条目以找到该树,或者如果该树未列出,直接向维护者询问。

描述你的更改

描述你的问题。无论你的补丁是一行的错误修复还是 5000 行的新功能,都必定有一个促使你进行此项工作的潜在问题。说服审阅者确实存在一个值得修复的问题,并且让他们继续阅读第一段以下的内容是有意义的。

描述用户可见的影响。直接的崩溃和死锁相当具有说服力,但并非所有 bug 都那么显眼。即使是在代码审查期间发现的问题,也要描述你认为它对用户可能产生的影响。请记住,大多数 Linux 安装运行的是辅助稳定版树或特定于供应商/产品的树中的内核,这些树仅从上游挑选(cherry-pick)特定的补丁,因此请包含任何有助于将你的更改路由到下游的信息:触发环境、dmesg 摘录、崩溃描述、性能回归、延迟尖峰、死锁等。

量化优化和权衡。如果你声称在性能、内存消耗、栈占用或二进制大小时有所改进,请提供支持这些说法的数字。但同时也要描述不那么显而易见的成本。优化通常不是免费的,而是 CPU、内存和可读性之间的权衡;或者在启发式算法的情况下,是在不同工作负载之间的权衡。描述你的优化的预期缺点,以便审阅者权衡成本与收益。

一旦确立了问题,请用技术细节描述你为解决它实际采取的措施。用通俗易懂的语言描述更改非常重要,以便审阅者验证代码的行为是否符合你的预期。

如果你将补丁描述写成可以轻松作为“提交日志(commit log)”拉取到 Linux 源代码管理系统 git 中的形式,维护者会非常感激。请参见 规范的补丁格式

每个补丁只解决一个问题。如果你的描述开始变得很长,这是一个信号,表明你可能需要拆分补丁。请参见 拆分你的更改

当你提交或重新提交补丁或补丁系列时,请包含完整的补丁描述及其理由。不要仅仅说这是该补丁(系列)的第 N 版。不要指望子系统维护者去回看早期版本的补丁或引用的 URL 来寻找补丁描述并将其放入补丁中。换句话说,补丁(系列)及其描述应该是自包含的。这有利于维护者和审阅者。有些审阅者可能甚至没有收到过早期版本的补丁。

用祈使语气描述你的更改,例如“make xyzzy do frotz”而不是“[This patch] makes xyzzy do frotz”或“[I] changed xyzzy to do frotz”,就像你在向代码库下达命令以改变其行为一样。

如果你想引用某个特定的提交,请不要仅仅引用该提交的 SHA-1 ID。请同时包含该提交的一行摘要(oneline summary),以便审阅者更容易知道它讲的是什么。例如

Commit e21d2170f36602ae2708 ("video: remove unnecessary
platform_set_drvdata()") removed the unnecessary
platform_set_drvdata(), but left the variable "dev" unused,
delete it.

你还应确保使用 SHA-1 ID 的前十二个字符。内核仓库包含大量对象,使用较短, 的 ID 发生碰撞的可能性是切实存在的。请记住,即使现在你的六字符 ID 没有发生碰撞,五年后这种情况也可能会改变。

如果在网上可以找到与该更改相关的讨论或任何其他背景信息,请添加指向它的 “Link:” 标签。如果该补丁是某些早期邮件列表讨论的结果或是网上记录的内容,请指向它。

当链接到邮件列表存档时,最好使用 lore.kernel.org 邮件存档服务。要创建链接 URL,请使用消息的 Message-ID 头部的内容(去掉周围的尖括号)。例如

Link: https://lore.kernel.org/30th.anniversary.repost@klaava.Helsinki.FI

请检查链接,确保它确实有效并指向相关消息。

但是,尽量让你的解释在没有外部资源的情况下也能被理解。除了提供邮件列表存档或 bug 的 URL 之外,还要总结导致提交该补丁的讨论的相关要点。

如果你的补丁修复了一个 bug,请使用 ‘Closes:’ 标签以及一个指向邮件列表存档中报告或公共 bug 跟踪器的 URL。例如

Closes: https://example.com/issues/1234

一些 bug 跟踪器能够在应用带有此类标签的提交时自动关闭问题。一些监控邮件列表的机器人也可以跟踪此类标签并采取某些操作。禁止使用私有 bug 跟踪器和无效的 URL。

如果你的补丁修复了特定提交中的 bug,例如你使用 git bisect 发现了问题,请使用 ‘Fixes:’ 标签,并包含至少前 12 个字符的 SHA-1 ID 以及一行摘要。不要将标签跨多行拆分,为了简化解析脚本,标签可以豁免“在 75 列处换行”的规则。例如

Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")

可以使用以下 git config 设置来添加一种优美的格式,以便在 git loggit show 命令中按上述风格输出

[core]
        abbrev = 12
[pretty]
        fixes = Fixes: %h (\"%s\")

调用示例

$ git log -1 --pretty=fixes 54a4f0239f2e
Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")

拆分你的更改

将每个逻辑更改拆分为独立的补丁。

例如,如果你的更改既包含单个驱动程序的 bug 修复又包含性能增强,请将这些更改拆分为两个或更多补丁。如果你的更改包含 API 更新以及使用该新 API 的新驱动程序,请将它们拆分为两个补丁。

另一方面,如果你对许多文件做了同一项更改,请将这些更改组合到一个补丁中。因此,一个逻辑更改包含在一个补丁中。

需要记住的一点是,每个补丁都应该做出易于理解、可由审阅者验证的更改。每个补丁都应该凭其自身的价值经得起检验。

如果一个补丁依赖于另一个补丁才能使更改完整,那是可以的。只需在你的补丁描述中注明 “此补丁依赖于补丁 X(this patch depends on patch X)”

将更改划分为一系列补丁时,要特别注意确保内核在系列中的每个补丁之后都能正确编译和运行。使用 git bisect 追踪问题的开发者可能会在任何点中断你的补丁系列;如果你在中间引入了 bug,他们可不会感谢你。

如果你无法将补丁集浓缩为更小的补丁集,那么每次只发布大约 15 个左右的补丁,并等待审查和集成。

检查你的更改风格

检查你的补丁是否存在基本的风格违规,其详细信息可以在 Linux 内核编码风格 中找到。不这样做只会浪费审阅者的时间,并会导致你的补丁被拒绝,甚至可能在未被阅读时就被拒绝。

一个重大的例外是将代码从一个文件移动到另一个文件 —— 在这种情况下,你不应该在移动代码的同一个补丁中对被移动的代码进行任何修改。这清晰地划分了移动代码的行为与你的更改。这极大地有助于审查实际的差异,并允许工具更好地追踪代码本身的历程。

在提交之前,使用补丁风格检查器(scripts/checkpatch.pl)检查你的补丁。但请注意,风格检查器应被视为指南,而不是人类判断的替代品。如果你的代码违反了某些规范但看起来更好,那么最好还是保持原样。

检查器报告三个级别
  • ERROR(错误):极有可能是错误的事情

  • WARNING(警告):需要仔细审查的事情

  • CHECK(检查):需要思考的事情

你应该能够为补丁中保留的所有违规项给出合理的解释。

为你的补丁选择收件人

对于任何涉及他们维护的代码的补丁,你都应该抄送(CC)相应的子系统维护者和列表;浏览 MAINTAINERS 文件和源码修订历史以了解这些维护者是谁。脚本 scripts/get_maintainer.pl 在这一步骤中非常有用(将你的补丁路径作为参数传递给 scripts/get_maintainer.pl)。如果你找不到你正在处理的子系统的维护者,Andrew Morton(akpm@linux-foundation.org)将作为最后防线的维护者。

默认情况下,所有补丁都应该使用 linux-kernel@vger.kernel.org,但该列表的高流量导致许多开发者将其屏蔽。不过,请不要向无关的列表和无关人员发送垃圾邮件。

许多与内核相关的列表托管在 kernel.org 上;你可以在 https://subspace.kernel.org 找到它们的列表。不过,也有在其他地方托管的内核相关列表。

Linus Torvalds 是所有被接受进入 Linux 内核的更改的最终仲裁者。他的电子邮箱地址是 <torvalds@linux-foundation.org>。他收到了大量的电子邮件,目前只有极少数补丁直接通过 Linus,因此通常你应该尽最大努力 -避免- 发电子邮件给他。

如果你有一个修复可利用的安全漏洞的补丁,请将该补丁发送至 security@kernel.org。对于严重的 bug,可以考虑实施短暂的禁运期(embargo),以便发行版能够将补丁分发给用户;在这种情况下,显然不应将补丁发送到任何公开列表。另请参阅 安全漏洞

修复已发布内核中严重 bug 的补丁应该通过在补丁的签名区放置类似下面这样的一行来指向稳定版维护者

Cc: stable@vger.kernel.org

(注意,这不是电子邮件收件人)。除了本文档之外,你还应该阅读 关于 Linux -stable 版本你所需要知道的一切

如果更改影响了用户空间与内核的接口,请向 MAN-PAGES 维护者(如 MAINTAINERS 文件中所列)发送一个 man-pages 补丁,或者至少发送一份更改通知,以便将一些信息纳入手册页(manual pages)。用户空间 API 更改也应该抄送至 linux-api@vger.kernel.org

回应审查意见

你的补丁几乎肯定会收到来自审阅者关于如何改进补丁的评论,这些评论通常以回复你电子邮件的形式出现。你必须回应这些评论;忽视审阅者是让自己也被忽视的绝佳途径。你只需回复他们的电子邮件来回答他们的评论。未导致代码更改的审查评论或问题,也几乎肯定应该带来一条评论或变更日志条目,以便下一个审阅者更好地理解正在发生的事情。

务必告诉审阅者你做了哪些更改,并感谢他们抽出时间。代码审查是一个累人且耗时的过程,审阅者有时会脾气暴躁。不过,即使在这种情况下,也要礼貌地回应并解决他们指出的问题。在发送下一个版本时,请在求职信(cover letter)或各个补丁中添加一个 补丁变更日志(patch changelog),解释与先前提交相比的区别(请参见 规范的补丁格式)。通过将对你的补丁发表过评论的人添加到补丁的 CC 列表中,来通知他们新版本的情况。

有关电子邮件客户端的建议和邮件列表礼仪,请参见 Linux 电子邮件客户端信息

在邮件讨论中使用精简的交叉回复

在 Linux 内核开发讨论中强烈不鼓励置顶回复(Top-posting)。交叉回复(或称“内联”回复)使得对话更容易跟踪。有关更多详细信息,请参见:https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

正如邮件列表上经常引用的那样

A: http://en.wikipedia.org/wiki/Top_post
Q: Where do I find info about this thing called top-posting?
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing in e-mail?

同样,请删减所有与你的回复无关的不需要的引用。这使得响应更容易找到,并节省了时间和空间。有关更多详细信息,请参见:http://daringfireball.net/2007/07/on_top

A: No.
Q: Should I include quotations after my reply?

不要气馁 —— 也不要不耐烦

提交更改后,请耐心等待。审阅者是大忙人,可能无法立即处理你的补丁。

曾几何时,补丁常常无声无息地消失在虚空中,但现在的开发过程比以前更顺畅了。你通常应该在几周内(通常是 2-3 周)收到评论;如果没有收到,请确保你将补丁发送到了正确的地方。在重新提交或 ping 审阅者之前,请至少等待一周 —— 在合并窗口(merge windows)等繁忙时期可能需要更长时间。

在几周后重新发送补丁或补丁系列,并在主题行中加上“RESEND”字样也是可以的

[PATCH Vx RESEND] sub/sys: Condensed patch summary

当你提交修改后的补丁或补丁系列版本时,不要添加“RESEND” —— “RESEND”仅适用于与先前提交相比没有任何修改的补丁或补丁系列的重新提交。

在主题中包含 PATCH

由于发往 Linus 和 linux-kernel 的电子邮件流量很大,惯例是在你的主题行前加上 [PATCH] 前缀。这可以让 Linus 和其他内核开发者更容易地将补丁与其他电子邮件讨论区分开来。

git send-email 会自动为你完成此操作。

签署你的工作 —— 开发者原产地证明

为了更好地追踪谁做了什么,特别是对于那些可能通过多层维护者最终渗入内核中最终归宿的补丁,我们在通过电子邮件流转的补丁上引入了“签署(sign-off)”程序。

签名是补丁解释末尾的一行简单文本,它证明你编写了该补丁,或者拥有将其作为开源补丁传递的其他权利。规则非常简单:如果你能证明以下内容

开发者原产地证明 1.1

通过对本项目做出贡献,我证明:

  1. 此贡献完全或部分由我创作,我有权根据文件中指明的开源许可证提交它;或者

  2. 此贡献基于以前的工作,据我所知,该工作受适当的开源许可证管辖,我有权根据该许可证在文件中指明的相同开源许可证下提交包含由我全部或部分创作的修改的工作(除非允许我在不同的许可证下提交);或者

  3. 此贡献是由其他人直接提供给我的,该人证明了 (a)、(b) 或 (c),并且我没有修改它。

  4. 我理解并同意,本项目和该贡献是公开的,并且该贡献的记录(包括我随其提交的所有个人信息,包括我的签名)将无限期地保留,并可根据本项目或所涉及的开源许可证进行重新分发。

那么你只需添加一行,内容如下

Signed-off-by: Random J Developer <random@developer.example.org>

使用已知的身份(抱歉,不接受匿名贡献)。如果你使用 git commit -s,系统会自动为你完成此操作。回退(reverts)也应包含 “Signed-off-by”。git revert -s 会为你自动完成。

有些人还会在末尾添加额外的标签。目前它们会被忽略,但你可以这样做来标记公司内部流程,或者指出关于签名的某些特殊细节。

作者 SoB 之后的任何进一步 SoB(Signed-off-by:)均来自处理和传递该补丁但未参与其开发的人员。SoB 链应该反映补丁在传播给维护者并最终传播给 Linus 过程中所走的真实路线,其中第一个 SoB 条目表示单个作者的主要著作权。

何时使用 Acked-by:、Cc: 和 Co-developed-by:

Signed-off-by: 标签表示签名者参与了补丁的开发,或者他/她位于补丁的传递路径中。

如果某人没有直接参与补丁的准备或处理,但希望表示并记录其对该补丁的批准,则他们可以要求在补丁的变更日志中添加 Acked-by: 行。

Acked-by: 旨在由以某种方式对受影响代码负责或参与其中的人使用。最常见的情况是,当维护者既没有贡献也没有转发该补丁时,由该维护者使用。

Acked-by: 也可由其他利益相关者使用,例如具备领域知识的人(例如被修改代码的原作者)、内核 uAPI 补丁的用户空间侧审阅者或某功能的关键用户。在这些情况下,可选地添加一个“# 后缀(# Suffix)”来澄清其含义可能会很有用

Acked-by: The Stakeholder <stakeholder@example.org> # As primary user

Acked-by: 不如 Signed-off-by: 那般正式。它是一个记录,表明确认者(acker)至少审查了该补丁并表示接受。因此,补丁合并者有时会手动将确认者的“嗯,看起来不错(yep, looks good to me)”转换为 Acked-by:(但请注意,通常最好请求明确的 ack)。

Acked-by: 也比 Reviewed-by: 不那么正式。例如,维护者可能会用它来表示他们同意补丁合入,但他们可能不像提供 Reviewed-by: 那样彻底地审查了它。同样,关键用户可能没有对补丁进行技术审查,但他们可能对整体方法、功能或面向用户的接口感到满意。

Acked-by: 不一定表示对整个补丁的确认。例如,如果一个补丁影响了多个子系统,并且得到了某个子系统维护者的 Acked-by:,这通常仅表示对影响该维护者代码的那部分的确认。这里应当运用判断力。如有疑问,人们应参考邮件列表存档中的原始讨论。在这种情况下也可以使用“# 后缀”来澄清。

如果某人有机会对补丁发表评论,但未提供此类评论,你可以选择性地向补丁添加 Cc: 标签。此标签记录了潜在的利益相关方已被纳入讨论。注意,这是你可能无需被命名之人的明确许可即可使用的仅有的三个标签之一(有关详细信息,请参见下文的“标记他人需要获得许可”)。

Co-developed-by: 表明该补丁是由多位开发者共同创作的;当多个人共同完成一个补丁时,它用于给予共同作者署名(除了 From: 标签署名的作者之外)。由于 Co-developed-by: 表示署名权,每个 Co-developed-by: 之后必须紧跟相关共同作者的 Signed-off-by:。标准的签名程序适用,即 Signed-off-by: 标签的排序应尽可能反映补丁的按时间顺序的历史,无论作者是通过 From: 还是 Co-developed-by: 署名。值得注意的是,最后一个 Signed-off-by: 必须始终是提交补丁的开发者的签名。

注意,当 From: 作者同时也是电子邮件头部 From: 行中列出的人(及其电子邮件)时,From: 标签是可选的。

由 From: 作者提交的补丁示例

<changelog>

Co-developed-by: First Co-Author <first@coauthor.example.org>
Signed-off-by: First Co-Author <first@coauthor.example.org>
Co-developed-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>

由 Co-developed-by: 作者提交的补丁示例

From: From Author <from@author.example.org>

<changelog>

Co-developed-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>

使用 Reported-by:、Tested-by:、Reviewed-by:、Suggested-by: 和 Fixes:

Reported-by 标签向发现并报告 bug 的人致谢,并希望以此激励他们在未来再次帮助我们。该标签专门用于 bug;请不要将其用于功能请求的致谢。该标签后面应跟一个指向该报告的 Closes: 标签,除非该报告在网上不可用。如果补丁修复了所报告问题的一部分,则可以使用 Link: 标签代替 Closes:。注意,Reported-by 标签是你可能无需被命名之人的明确许可即可使用的仅有的三个标签之一(有关详细信息,请参见下文的“标记他人需要获得许可”)。

Tested-by: 标签表示命名的人员已(在某些环境中)成功测试了该补丁。该标签告知维护者已经进行了一些测试,提供了一种为未来补丁寻找测试人员的方法,并确保对测试人员进行致谢。

相反,Reviewed-by: 表示根据审阅者的声明,该补丁已经过审查并被认为是可接受的

审查者的监督声明

通过提供我的 Reviewed-by: 标签,我声明:

  1. 我对该补丁进行了技术审查,以评估其并入主线内核的适当性和就绪性。

  2. 与该补丁有关的任何问题、顾虑或疑问均已传达给提交者。我对提交者对我所提意见的回应感到满意。

  3. 虽然此次提交中可能还有可以改进的地方,但我认为在当前情况下,它是 (1) 对内核有价值的修改,且 (2) 没有会导致反对将其纳入的已知问题。

  4. 虽然我已经审查了该补丁并认为它是健康的,但我并不(除非在其他地方明确说明)做出任何保证或担保,即它在任何给定情况下都能实现其既定目的或正常运行。

Reviewed-by 标签是一种意见声明,认为该补丁是对内核的适当修改,且没有任何残留的严重技术问题。任何感兴趣的审阅者(完成了工作且身份已知的人)都可以为补丁提供 Reviewed-by 标签。此标签用于向审阅者致谢,并告知维护者对该补丁进行的审查程度。当由精通该主题领域并执行彻底审查的知名审阅者提供 Reviewed-by: 标签时,通常会增加你的补丁进入内核的可能性。

一旦在邮件列表上从测试人员或审阅者那里收到 Tested-by 和 Reviewed-by 标签,作者在发送下一个版本时应将它们添加到适用的补丁中。然而,如果补丁在随后的版本中发生了重大变化,这些标签可能不再适用,因此应予以移除。通常,移除某人的 Acked-by、Tested-by 或 Reviewed-by 标签时,应在补丁变更日志中加以提及并附带解释(在 ‘---’ 分隔符之后)。

Suggested-by: 标签表示补丁的构想是由被命名的人建议的,并确保对该构想提出者进行致谢:如果我们勤勉地对构想提供者进行致谢,希望他们会在未来受到启发再次帮助我们。注意,这是你可能无需被命名之人的明确许可即可使用的仅有的三个标签之一(有关详细信息,请参见下文的“标记他人需要获得许可”)。

Fixes: 标签表示该补丁修复了先前提交中的 bug。它用于轻松确定问题起源于何处,这有助于审查 bug 修复。该标签还协助稳定版内核团队确定哪些稳定版内核版本应该接受你的修复。这是指示补丁修复了哪个 bug 的首选方法。有关更多详细信息,请参见 描述你的更改

注意:附加 Fixes: 标签既不会颠覆稳定版内核规则流程,也不会取消在所有稳定版补丁候选者上 Cc: stable@vger.kernel.org 的要求。有关更多信息,请阅读 关于 Linux -stable 版本你所需要知道的一切

最后,虽然提供标签是受欢迎的且通常非常受感激,但请注意,签名者(即提交者和维护者)可以自行决定是否应用所提供的标签。

标记他人需要获得许可

在向你的补丁添加上述标签时要小心,因为除了 Cc:、Reported-by: 和 Suggested-by: 之外,所有其他标签都需要被命名之人的明确许可。对于这三个标签,如果根据 lore 存档或提交历史,该人曾使用该姓名和电子邮件地址对 Linux kernel 做过贡献 —— 并且对于 Reported-by: 和 Suggested-by: 而言是在公开场合进行了报告或建议,则隐式许可就足够了。注意,从这个意义上说,bugzilla.kernel.org 是一个公共场所,但在那里使用的电子邮件地址是私密的;因此不要在标签中暴露它们,除非该人在之前的贡献中使用过它们。

使用 Assisted-by:

如果在创建补丁的过程中使用了任何高级编码工具,你需要通过添加 Assisted-by 标签来承认这种使用。未能这样做可能会阻碍你的工作被接受。有关致谢编码助手的详细信息,请参见 AI 编码助手

规范的补丁格式

本节描述了补丁本身应如何格式化。请注意,如果你的补丁存储在 git 仓库中,可以使用 git format-patch 获得适当的补丁格式。不过,工具无法自动创建必要的文本,因此无论如何请阅读下面的说明。

主题行

规范的补丁主题行为

Subject: [PATCH 001/123] subsystem: summary phrase

规范的补丁消息正文包含以下内容

  • 指定补丁作者的 from 行,后跟一个空行(仅在发送补丁的人不是作者时需要)。

  • 解释的正文,在 75 列处换行,该正文将被复制到永久变更日志中以描述此补丁。

  • 一个空行。

  • 如上所述的 Signed-off-by: 行,它们也将进入变更日志。

  • 仅包含 --- 的标记行。

  • 不适合放入变更日志的任何附加评论。

  • 实际的补丁(diff 输出)。

主题行格式使得按主题行对电子邮件进行字母排序变得非常容易 —— 几乎任何电子邮件阅读器都支持这一点 —— 因为序号是零填充的,所以数字排序和字母排序是一样的。

电子邮件主题中的 subsystem(子系统)应标识正在打补丁的内核区域或子系统。

电子邮件主题中的 summary phrase(摘要短语)应简明扼要地描述该电子邮件包含的补丁。summary phrase 不应是文件名。不要在整个补丁系列中的每个补丁都使用相同的 summary phrase(其中 patch series 是多个相关补丁的有序序列)。

请记住,你电子邮件的 summary phrase 会成为该补丁的全局唯一标识符。它一直传播到 git 变更日志中。summary phrase 以后可能会用于引用该补丁的开发者讨论中。人们会想要通过谷歌搜索 summary phrase 来阅读关于该补丁的讨论。当两三个月后人们使用诸如 gitkgit log --oneline 等工具浏览成千上万个补丁时,这也将是他们能够快速看到的唯一内容。

出于这些原因,summary 必须不超过 70-75 个字符,并且它必须同时描述补丁更改了什么,以及为什么该补丁可能是必要的。要做到既简明又具描述性是具有挑战性的,但这正是一份写得好的摘要应该做到的。

summary phrase 可以前置方括号括起来的标签:“Subject: [PATCH <tag>...] <summary phrase>”。这些标签不被视为摘要短语的一部分,而是描述应如何处理该补丁。常见的标签可能包括版本描述符(如果为了响应评论而发送了补丁的多个版本,即“v1, v2, v3”),或者用“RFC”表示征求意见(Request for Comments)。

如果一个补丁系列中有四个补丁,各个补丁可以这样编号:1/4、2/4、3/4、4/4。这确保了开发者能够理解应按什么顺序应用这些补丁,并确保他们已经审查或应用了该补丁系列中的所有补丁。

以下是一些优秀的主题示例

Subject: [PATCH 2/5] ext2: improve scalability of bitmap searching
Subject: [PATCH v2 01/27] x86: fix eflags tracking
Subject: [PATCH v2] sub/sys: Condensed patch summary
Subject: [PATCH v2 M/N] sub/sys: Condensed patch summary

From 行

from 行必须是消息正文中的第一行,其格式为

From: Patch Author <author@example.com>

from 行指定了在永久变更日志中谁将被署名为补丁作者。如果缺少 from 行,则将使用电子邮件头部中的 From: 行来确定变更日志中的补丁作者。

作者可以通过在 fromSoB 行中添加组织名称来表明其所属机构或工作的赞助商,例如

From: Patch Author (Company) <author@example.com>

解释正文

解释正文将被提交到永久的源代码变更日志中,因此对于一个早已忘记可能导致此补丁的讨论的直接细节的胜任的读者来说,它应该是有意义的。包含该补丁所解决的失败症状(内核日志消息、oops 消息等)对那些可能在提交日志中搜索适用补丁的人特别有用。文本编写得应该足够详细,以便在几周、几个月甚至几年后阅读时,能为读者提供必要细节,以理解创建该补丁的原因

如果补丁修复了编译失败,可能没有必要包含_所有_编译失败信息;只需包含足够多的信息,使得搜索该补丁的人能够找到它即可。正如在 summary phrase 中一样,做到既简明又具描述性是很重要的。

提交消息中的回溯信息(Backtraces)

回溯有助于记录导致问题的调用链。然而,并非所有回溯都有帮助。例如,早期引导调用链是独特且显而易见的。但是,逐字复制完整的 dmesg 输出会添加诸如时间戳、模块列表、寄存器和栈转储等会分散注意力的信息。

因此,最实用的回溯应该从转储中提炼出相关信息,这使得更容易专注于真正的问题。以下是一个精简良好的回溯示例

unchecked MSR access error: WRMSR to 0xd51 (tried to write 0x0000000000000064)
at rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
Call Trace:
mba_wrmsr
update_domains
rdtgroup_mkdir

评注

--- 标记行具有关键作用,它向补丁处理工具标记变更日志消息在何处结束。

--- 标记之后附加注释的一个好用途是用于 diffstat,以显示哪些文件发生了更改,以及每个文件插入和删除的行数。diffstat 对于较大的补丁特别有用。如果你打算在 --- 标记之后包含 diffstat,请使用 diffstat 选项 -p 1 -w 70,以便文件名从内核源码树的顶部开始列出,并且不会占用太多水平空间(可以轻松放入 80 列内,可能带有某些缩进)。(git 默认会生成适当的 diffstat。)

仅与当前时刻或维护者相关、不适合放入永久变更日志的其他评论也应该放在这里。此类评论的一个好例子是描述补丁 v1 和 v2 版本之间变化的 patch changelogs(补丁变更日志)。

请将此信息放在将变更日志与补丁其余部分分隔开的 ---之后。版本信息不是提交到 git 树的变更日志的一部分。它是供审阅者的附加信息。如果它放在提交标签上方,则需要手动交互来删除它。如果它在分隔线下方,应用补丁时它会自动被剥离。如果可用,建议添加指向补丁以前版本的链接(例如,lore.kernel.org 存档链接)以帮助审阅者

<commit message>
...
Signed-off-by: Author <author@mail>
---
V2 -> V3: Removed redundant helper function
V1 -> V2: Cleaned up coding style and addressed review comments

v2: https://lore.kernel.org/bar
v1: https://lore.kernel.org/foo

path/to/file | 5+++--
...

有关正确补丁格式的更多详细信息,请参见以下参考资料。

显式的 In-Reply-To 头部

手动向补丁添加 In-Reply-To: 头部(例如,在使用 git send-email 时)以将补丁与先前的相关讨论关联起来可能会很有帮助,例如将 bug 修复链接到带有 bug 报告的电子邮件。但是,对于多补丁系列,通常最好避免使用 In-Reply-To: 链接到该系列的旧版本。这样,补丁的多个版本就不会在电子邮件客户端中变成无法管理的引用森林。如果链接有帮助,你可以使用 https://lore.kernel.org/ 重定向器(例如在求职信文本中)链接到补丁系列的早期版本。

提供基准树信息

当其他开发者收到你的补丁并开始审查过程时,考虑到当今存在大量的维护者树,他们绝对有必要知道你的工作基于哪个基准提交/分支(base commit/branch)。再次注意上面解释过的 MAINTAINERS 文件中的 T: 条目。

对于试图运行一系列测试以在维护者开始审查之前确定你的提交质量的自动化 CI 进程来说,这一点更为重要。

如果你使用 git format-patch 生成补丁,你可以通过使用 --base 标志自动在提交中包含基准树信息。使用此选项最简单、最方便的方法是结合主题分支(topical branches)

$ git checkout -t -b my-topical-branch master
Branch 'my-topical-branch' set up to track local branch 'master'.
Switched to a new branch 'my-topical-branch'

[perform your edits and commits]

$ git format-patch --base=auto --cover-letter -o outgoing/ master
outgoing/0000-cover-letter.patch
outgoing/0001-First-Commit.patch
outgoing/...

当你打开 outgoing/0000-cover-letter.patch 进行编辑时,你会注意到它在最底部有一个 base-commit: 尾随块(trailer),这为审阅者和 CI 工具提供了足够的信息来正确执行 git am 而无需担心冲突

$ git checkout -b patch-review [base-commit-id]
Switched to a new branch 'patch-review'
$ git am patches.mbox
Applying: First Commit
Applying: ...

有关此选项的更多信息,请参见 man git-format-patch

注意

--base 功能是在 git 2.9.0 版本中引入的。

如果你没有使用 git 来格式化补丁,你仍然可以包含相同的 base-commit 尾随块来指示你的工作所基于的树的提交哈希。你应该将其添加到求职信中,或者添加到系列中的第一个补丁中,并且它应该放在 --- 行下方或所有其他内容的最底部、紧挨着你的电子邮件签名之前。

确保基准提交位于官方维护者/主线树中,而不是在某些内部的、仅你可访问的树中 —— 否则它将毫无价值。

工具

此过程的许多技术方面可以使用 b4 自动化,其文档位于 <https://b4.docs.kernel.org/en/latest/>。这可以帮助完成诸如跟踪依赖项、运行 checkpatch 以及格式化和发送邮件之类的事情。

参考资料

Andrew Morton,“完美的补丁”(The perfect patch,简称 tpp)。

<https://www.ozlabs.org/~akpm/stuff/tpp.txt>

Jeff Garzik,“Linux 内核补丁提交格式”。

<https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>

Greg Kroah-Hartman,“如何惹恼内核子系统维护者”。

<http://www.kroah.com/log/linux/maintainer.html>

<http://www.kroah.com/log/linux/maintainer-02.html>

<http://www.kroah.com/log/linux/maintainer-03.html>

<http://www.kroah.com/log/linux/maintainer-04.html>

<http://www.kroah.com/log/linux/maintainer-05.html>

<http://www.kroah.com/log/linux/maintainer-06.html>

内核 Linux 内核编码风格

Linus Torvalds 关于规范补丁格式的邮件

<https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>

Andi Kleen,“关于提交内核补丁”

合并困难或有争议的更改的一些策略。

http://halobates.de/on-submitting-patches.pdf