本文翻译自The Linux Foundation的《How to Participate in the Linux Community》(基于2012-03-21最新版本),原作者为Jonathan Corbet(corbet@lwn.net)。 下面是该文章第五章节的中译文。

 
5、发布补丁
 
迟早有一天你的工作将提交到开发社区进行评审,并最终合入内核主线。不出所料,内核开发社区在发布补丁方面已经逐步形成了一套约定和程序;遵循这 些约定和程序将使得开发者们的工作变得更加轻松。本文将尝试适当详尽地对这方面的内容进行说明;更多内容可以参考内核文档目录下的 SubmittingPatches、SubmittingDrivers和SubmitChecklist文档。
 
5.1、何时发布
 
一直存在这样一种诱惑:在补丁完全"具备条件"之前不要发布补丁。对于简单的补丁,这不是问题。但如果补丁的工作比较复杂,则在补丁完成前,很多事情需要从开发社区获取的反馈中得到。因此你应该考虑将正在进行中的工作发布给社区,或者甚至可以提供一个可用的git源码树,让那些对你的补丁感兴趣的开发者随时了解到你的工作进展。
 
当发布一些尚不具备被合入内核条件的代码时,最好在发布时如实告知社区。同时要说明还有哪些主要工作尚待去做以及所有已知的问题。与已完成的补丁相比,那些已知尚未完成的补丁获得的青睐更少,但那些确实提出想法的人能够帮助你始终工作在正确的方向上。
 
5.2、在补丁创建之前
 
在你考虑将补丁发布到开发社区之前,有一些事情是需要预先做的,这些事情包括:
 
  * 尽你所能的对补丁代码进行测试。充分利用内核调试工具,确保内核可以在所有合理的配置选项组合下编译,使用跨平台编译器进行不同体系的构建,等等。
 
  * 确保你的代码与内核编码风格准则兼容。
 
  * 你的变化会对内核性能有影响吗?如果有的话,你应该运行基准测试来看看你的改变对内核的具体影响(或带来的好处);补丁中应该包含这个测试结果的总结。
 
  * 确保你有权发布这个补丁代码。如果代码是为某个雇佣者开发的,雇佣者很可能才是这段代码的真正拥有者,那么雇佣者必须同意补丁在GPL许可证下发布。
 
一般来说,在发布代码之前多做一些考虑总是会在短时间内让你的付出收到回报的。
 
5.3、补丁准备
 
补丁发布准备的工作量可能十分巨大,不过,再重申一遍,即便是短期内尝试在这个阶段节省时间通常也是不可取的。
 
补丁必须是为某一个特定的内核版本而准备的。通常,补丁应该基于linus的git树中的当前主线版本。但为了能让补丁得到更为广泛的测试和评审,制作针对-mm、linux-next或某个子系统树的补丁版本可能会变得很必要。针对其他源码树的补丁可能需要大量工作来解决代码冲突以及处理API的改变,这取决于你的补丁所在的领域以及其他方面的当前进展情况。
 
只有最简单的改变才应该以一个单独的补丁形式提供;其他所有补丁都应该由一系列合理的改变组成。拆分补丁是一门艺术;一些开发者花费很长时间考虑如何以一种开发社区期望的方式进行补丁拆分。下面是一些经验法则,但却相当有帮助:
 
  * 你发布的补丁序列决不应该仅仅是你的版本控制系统下的一系列改变。相反,你应该考虑这些改变的最终形式,将他们分成有意义的若干部分。开发者只对离散的、自完备的改变感兴趣,而不是你提供的这些改变的路径信息。
 
  * 每个逻辑上独立的改变都应该以一个单独的补丁提供。这些改变可小("为这个结构体增加一个字段")可大(例如,增加一个重要的新驱动程序),但它们都应该是小概念的并且可用一行文字描述的。每个补丁所带来的改变都应该可以被独立评审和独立验证的。
 
  * 这里再次重申一下上面的准则:不要将不同类型的改变混在一个补丁中。如果一个单独的补丁修复了一个极其重要的安全bug、重新调整了一些结构体并且重新对代码进行了格式化,那么这个补丁很有可能被置之不理,这个重要的修复也将会丢失。
 
  * 每个补丁都应该生产出一个可以正确编译和运行的内核;即使你的补丁序列在中间被打断,结果仍然应该是一个可工作的内核。部分应用一个补丁序列是一种常见的情况,尤其是当"git bisect"工具被用于查找regression时;如果补丁序列被打断的结果是一个损坏的内核,则会导致那些参与追查内核问题的开发者和用户的工作更加困难。
 
  * 但也不要做的太过分。最近一个开发者将一个文件的多处修改放在500个补丁中发布 — 这一行为并没有使他成为内核邮件列表上最受欢迎的人。只要仍然包含一个单一的*逻辑*改变,一个单一的补丁也可以适当地大些。
 
  * 人们可能很想通过一系列的补丁来为内核增加一个完整的新基础设施,但直到这个系列的最后一个补丁生效,这个新设施才好用。这种想法应该尽可能的避免;如果这一系列补丁新增了regression,折半问题查找方法会把最后一个补丁视为导致问题罪魁祸首,即使真正的bug发生在别处。所以无论何时,添加了新代码的补丁都应该使得那些代码立即可用。
 
创建一个完美补丁的工作可能是一个令人沮丧的过程,这个过程将在"真正的编码工作"完成之后花费大量的时间和思考。但一旦正确地完成,你会感觉这个时间花费是值得的。
 
5.4、补丁格式化
 
现在,你已经有了一系列准备发布的完美补丁,但工作还远没有完成。每个补丁都需要被格式化为一条消息,这条消息可以快速清晰地将补丁的目的阐述给其他人。因而,每个补丁将由下面几个部分组成:
 
  * 一个可选的"From"行,用于指出补丁作者的名字。这一行只是在你通过mail对别人的补丁进行评论时才是必要的,并且在有疑问时加上这一行没有什么坏处。
 
  * 一行关于补丁做什么的描述。这行消息应该足以让一个读者在无需其他上下文信息提示的情况下确定这个补丁的范围;它就是将记录在简易格式的变更日志(changelog)中的那一行。这个消息的格式通常是以相关子系统的名字开头,后面跟随着这个补丁的目的。例如:
 
     gpio: fix build on CONFIG_GPIO_SYSFS=n
 
  * 在补丁内容的详细描述之后跟随一个空行。补丁内容描述的长度可以根据需要而定;这份描述应该说明补丁做了哪些事情以及为何该补丁应该被应用于内核。
 
  * 一个或多个标签(tag)行,至少应该有一个来自补丁作者的signed-off-by:行。接下来会有对标签(tags)的更为详细的说明。
 
上面的三项通常应该是提交补丁代码到版本控制系统时所使用的文本。后面跟着:
 
  * 补丁本身,使用统一标准的("-u")补丁格式。结合"-p"选项使用diff会将函数名字与改变相关联,结果可以使得补丁更易于被其他人阅读。
 
你应该避免在补丁中包含无关文件(比如那些由编译过程产生的文件或编辑器备份文件)的改变。Documentation目录下"dontdiff"在这方面可以提供帮助;在执行diff命令时使用"-X"选项。
 
上面提到的标签(tag)用于描述不同开发者是如何与此补丁的开发相关联的。在SubmittingPatches文档中有关于这方面的详细说明;下面是一个简要的总结。每行的格式是这样的:
 
  tag: Full Name <email address> optional-other-stuff
 
常用的标签如下:
 
  * Signed-off-by: 这是一个开发者有权提交可以被内核合并的补丁的证明。表示同意"Developer's Certificate of Origin"协议,该协议的全部文本内容可以在Documentation/SubmittingPatches中找到。没有正确signoff的代码将无法合并到内核主线中去。
 
  * Acked-by: 表明另外一名开发者(通常是相关代码的维护者)认可该补丁适合合并到内核中。
 
  * Tested-by: 说明这个人已经测试过这个补丁并发现它可以工作。
 
  * Reviewed-by: 这个签名的开发者已经对这个补丁的正确性进行了评审;在Documentation/SubmittingPatches中有关于"Reviewer's statement(评审者的声明)"的详尽描述。
 
  * Reported-by: 说明了这个补丁所修正的问题是哪个用户提出的;这个标签用于赞扬那些对内核代码进行测试并让大家知道什么时候内核无法正确工作的人(常常是未得到正确评价的)。
 
  * Cc: 列出哪些人会接收到一份补丁的拷贝并有机会对补丁进行评判。
 
在向你的补丁中添加标签时要小心:只有Cc:标签适合在没有得到指定名字的人的显式许可下添加。
 
5.5、发送补丁
 
在通过mail发送你的补丁之前,还有其他几个事情需要你小心处理:
 
  * 确认你的邮件发送程序不会破坏这个补丁?那些被邮件客户端工具无缘无故进行空白转换或换行的补丁将无法在另一端适用,并且常常无法被详细地检查。如果在这方面有任何疑问,可以先将补丁邮寄给你自己并确认补丁可以原封不动地展现。
    
   Documentation/email-clients.txt中有一些关于如何使特定的邮件客户端程序适合发送补丁的提示。
 
  * 确认你的补丁中已经没有愚蠢的错误了吗?你应该一直使用scripts/checkpatch.pl检查你的补丁并处理这个脚本提出的各种抱怨。不过请记住,虽然checkpatch.pl是对内核补丁应有的形式进行了大量思考后的体现,但它并不比你更聪明。如果为了修复一个checkpatch.pl的抱怨而使得代码变得更加糟糕,那就不要这么做。
 
补丁应该总是以普通文本形式发送。请不要以附件形式发送补丁;那样将会让评审者在回复中引用补丁部分内容时更加困难。直接将补丁放入邮件消息中即可。
 
在邮件发送补丁时,给那些可能对该补丁感兴趣的人发送一份补丁拷贝是很重要的。与其他一些项目不同,Linux内核项目鼓励大家在发送过多补丁拷贝方面犯错;千万不要假设相关人员会在邮件列表上看到你发布的补丁。尤其是,补丁拷贝应该发送给:
 
  * 受影响的子系统(s)的维护者(们)。前面曾经提到过,MAINTAINTERS文件是寻找这些维护者们的起点。
 
  * 其他曾工作在相同领域的开发者–尤其是那些可能正在此领域工作的人。使用git查看哪些人曾经修改过你正在修改的文件,这样做可能会很有帮助。
 
  * 如果你的补丁应对的是一个bug报告或一个特性请求,也发送一份补丁拷贝给原始问题或请求发起者。
 
  * 发送一份补丁拷贝到相关的邮件列表,如果找不到此类列表,那就发送到linux-kernel邮件列表。
 
  * 如果修复了一个bug,考虑一下该修复是否应该进入到下一个内核稳定版的更新版本中。如果应该进入,你应该给stable@kernel.org发送一份补丁的拷贝。同时也要在补丁内部标签中加入一条:"Cc: stable@kernel.org";这将使得内核稳定版维护小组在你的修复进入主线时收到一个通知。
 
当为一个补丁选择接收者时,最好对谁将最终接受并合并你的补丁做到心中有数。虽然将补丁直接发给Linus Torvalds并让他合并你的补丁是可能的,但事情通常不是这样做的。Linus非常忙,而且有各个子系统的维护者负责监视内核的某个特定部分。通常你将会让那个维护者合并你的补丁。如果没有专门的维护者,Andrew Morton常常作为补丁的最后依赖目标。
 
补丁需要一个好的标题行。补丁标题行的标准格式类似:
 
  [PATCH nn/mm] subsys: one-line description of the patch
 
这里"nn"是补丁的序号,"mm"是这个补丁序列的补丁总数,"subsys"是补丁所影响的子系统的名字。很显然,对于一个单一独立的补丁来说,nn/mm可以被省略的。
 
如果你有一个重要的补丁序列要提交,通常应该先发送一个介绍性的描述作为第零部分。但这个约定并不是被普遍遵循的;如果你使用这种方式,记住介绍部分的信息不会进入到内核的变更日志(changelog)中。因此要保证补丁自身包含完整的变更日志(changelog)信息。
 
通常,一个由多部分组成的补丁的第二以及接下来的部分应该以第一部分的答复(reply)的形式发送,这样他们在接收端才能组合在一起。像git和quilt这样的工具支持群发一批具有适当线索的补丁的命令。但是,如果你的补丁序列很长,且使用git,请使用–no-chain-reply-to命令行选项以避免创建过深的嵌套。

© 2012, bigwhite. 版权所有.

Related posts:

  1. 如何加入Linux内核开发社区(4)
  2. 如何加入Linux内核开发社区(2)
  3. 如何加入Linux内核开发社区(3)
  4. 如何加入Linux内核开发社区(1)
  5. 也谈Linux Kernel Hacking – 内核配置、编译与安装