.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/2.Process.rst <development_process>`

:Translator:

 时奎亮 Alex Shi <alex.shi@linux.alibaba.com>

:校译:

 吴想成 Wu XiangCheng <bobwxc@email.cn>

.. _cn_development_process:

开发流程如何进行
================

90年代早期的Linux内核开发是一件相当松散的事情,涉及的用户和开发人员相对较少。
由于拥有数以百万计的用户群,且每年有大约2000名开发人员参与进来,内核因此必须
发展出许多既定流程来保证开发的顺利进行。要参与到流程中来,需要对此流程的进行
方式有一个扎实的理解。

总览
----

内核开发人员使用一个松散的基于时间的发布过程,每两到三个月发布一次新的主要
内核版本。最近的发布历史记录如下:

	======  =================
	5.0	2019年3月3日
	5.1	2019年5月5日
	5.2	2019年7月7日
	5.3	2019年9月15日
	5.4	2019年11月24日
	5.5	2020年1月6日
	======  =================

每个5.x版本都是一个主要的内核版本,具有新特性、内部API更改等等。一个典型的5.x
版本包含大约13000个变更集,变更了几十万行代码。因此,5.x是Linux内核开发的前
沿;内核使用滚动开发模型,不断集成重大变化。

对于每个版本的补丁合并,遵循一个相对简单的规则。在每个开发周期的开头,“合并
窗口”被打开。这时,被认为足够稳定(并且被开发社区接受)的代码被合并到主线内
核中。在这段时间内,新开发周期的大部分变更(以及所有主要变更)将以接近每天
1000次变更(“补丁”或“变更集”)的速度合并。

(顺便说一句,值得注意的是,合并窗口期间集成的更改并不是凭空产生的;它们是经
提前收集、测试和分级的。稍后将详细描述该过程的工作方式。)

合并窗口持续大约两周。在这段时间结束时,Linus Torvalds将声明窗口已关闭,并
释放第一个“rc”内核。例如,对于目标为5.6的内核,在合并窗口结束时发生的释放
将被称为5.6-rc1。-rc1 版本是一个信号,表示合并新特性的时间已经过去,稳定下一
个内核的时间已经到来。

在接下来的6到10周内,只有修复问题的补丁才应该提交给主线。有时会允许更大的
更改,但这种情况很少发生;试图在合并窗口外合并新功能的开发人员往往受不到
友好的接待。一般来说,如果您错过了给定特性的合并窗口,最好的做法是等待下一
个开发周期。(偶尔会对未支持硬件的驱动程序进行例外;如果它们不改变已有代码,
则不会导致回归,应该可以随时被安全地加入)。

随着修复程序进入主线,补丁速度将随着时间的推移而变慢。Linus大约每周发布一次
新的-rc内核;在内核被认为足够稳定并最终发布前,一般会达到-rc6到-rc9之间。
然后,整个过程又重新开始了。

例如,这里是5.4的开发周期进行情况(2019年):

	==============  ==============================
	九月 15         5.3 稳定版发布
	九月 30         5.4-rc1 合并窗口关闭
	十月 6          5.4-rc2
	十月 13         5.4-rc3
	十月 20         5.4-rc4
	十月 27         5.4-rc5
	十一月 3        5.4-rc6
	十一月 10       5.4-rc7
	十一月 17       5.4-rc8
	十一月 24       5.4 稳定版发布
	==============  ==============================

开发人员如何决定何时结束开发周期并创建稳定版本?最重要的指标是以前版本的
回归列表。不欢迎出现任何错误,但是那些破坏了以前能工作的系统的错误被认为是
特别严重的。因此,导致回归的补丁是不受欢迎的,很可能在稳定期内删除。

开发人员的目标是在稳定发布之前修复所有已知的回归。在现实世界中,这种完美是
很难实现的;在这种规模的项目中,变数太多了。需要说明的是,延迟最终版本只会
使问题变得更糟;等待下一个合并窗口的更改将变多,导致下次出现更多的回归错误。
因此,大多数5.x内核都有一些已知的回归错误,不过,希望没有一个是严重的。

一旦一个稳定的版本发布,它的持续维护工作就被移交给“稳定团队”,目前由
Greg Kroah-Hartman领导。稳定团队将使用5.x.y编号方案不定期地发布稳定版本的
更新。要合入更新版本,补丁必须(1)修复一个重要的缺陷,且(2)已经合并到
下一个开发版本主线中。内核通常会在其初始版本后的一个以上的开发周期内收到
稳定版更新。例如,5.2内核的历史如下(2019年):

	==============  ===============================
        七月 7 	        5.2 稳定版发布
	七月 13	        5.2.1
	七月 21	        5.2.2
	七月 26	        5.2.3
	七月 28	        5.2.4
	七月 31	        5.2.5
	...	        ...
	十月 11         5.2.21
	==============  ===============================

5.2.21是5.2版本的最终稳定更新。

有些内核被指定为“长期”内核;它们将得到更长时间的支持。在本文中,当前的长期
内核及其维护者是:

	======  ================================	================
	3.16	Ben Hutchings				(长期稳定内核)
	4.4	Greg Kroah-Hartman & Sasha Levin	(长期稳定内核)
	4.9	Greg Kroah-Hartman & Sasha Levin
	4.14	Greg Kroah-Hartman & Sasha Levin
	4.19	Greg Kroah-Hartman & Sasha Levin
	5.4	Greg Kroah-Hartman & Sasha Levin
	======  ================================	================

长期支持内核的选择纯粹是维护人员是否有需求和时间来维护该版本的问题。
目前还没有为即将发布的任何特定版本提供长期支持的已知计划。

补丁的生命周期
--------------

补丁不会直接从开发人员的键盘进入主线内核。相反,有一个稍微复杂(如果有些非
正式)的过程,旨在确保对每个补丁进行质量审查,并确保每个补丁实现了一个在主线
中需要的更改。对于小的修复,这个过程可能会很快完成,,而对于较大或有争议的
变更,可能会持续数年。许多开发人员的沮丧来自于对这个过程缺乏理解或者试图绕过它。

为了减少这种挫败,本文将描述补丁如何进入内核。下面的介绍以一种较为理想化的
方式描述了这个过程。更详细的过程将在后面的章节中介绍。

补丁通常要经历以下阶段:

- 设计。这就是补丁的真正需求——以及满足这些需求的方式——所在。设计工作通常
  是在不涉及社区的情况下完成的,但是如果可能的话,最好是在公开的情况下完成
  这项工作;这样可以节省很多稍后再重新设计的时间。

- 早期评审。补丁被发布到相关的邮件列表中,列表中的开发人员会回复他们可能有
  的任何评论。如果一切顺利的话,这个过程应该会发现补丁的任何主要问题。

- 更广泛的评审。当补丁接近准备好纳入主线时,它应该被相关的子系统维护人员
  接受——尽管这种接受并不能保证补丁会一直延伸到主线。补丁将出现在维护人员的
  子系统树中,并进入 -next 树(如下所述)。当流程进行时,此步骤将会对补丁
  进行更广泛的审查,并发现由于将此补丁与其他人所做的工作合并而导致的任何
  问题。

- 请注意,大多数维护人员也有日常工作,因此合并补丁可能不是他们的最优先工作。
  如果您的补丁得到了需要更改的反馈,那么您应该进行这些更改,或者解释为何
  不应该进行这些更改。如果您的补丁没有评审意见,也没有被其相应的子系统或
  驱动程序维护者接受,那么您应该坚持不懈地将补丁更新到当前内核使其可被正常
  应用,并不断地发送它以供审查和合并。

- 合并到主线。最终,一个成功的补丁将被合并到由LinusTorvalds管理的主线存储库
  中。此时可能会出现更多的评论和/或问题;对开发人员来说应对这些问题并解决
  出现的任何问题仍很重要。

- 稳定版发布。大量用户可能受此补丁影响,因此可能再次出现新的问题。

- 长期维护。虽然开发人员在合并代码后可能会忘记代码,但这种行为往往会给开发
  社区留下不良印象。合并代码消除了一些维护负担,因为其他人将修复由API更改
  引起的问题。但是,如果代码要长期保持可用,原始开发人员应该继续为代码负责。

内核开发人员(或他们的雇主)犯的最大错误之一是试图将流程简化为一个“合并到
主线”步骤。这种方法总是会让所有相关人员感到沮丧。

补丁如何进入内核
----------------

只有一个人可以将补丁合并到主线内核存储库中:Linus Torvalds。但是,在进入
2.6.38内核的9500多个补丁中,只有112个(大约1.3%)是由Linus自己直接选择的。
内核项目已经发展到一个没有一个开发人员可以在没有支持的情况下检查和选择每个
补丁的规模。内核开发人员处理这种增长的方式是使用围绕信任链构建的助理系统。

内核代码库在逻辑上被分解为一组子系统:网络、特定体系结构支持、内存管理、视
频设备等。大多数子系统都有一个指定的维护人员,其总体负责该子系统中的代码。
这些子系统维护者(松散地)是他们所管理的内核部分的“守门员”;他们(通常)
会接受一个补丁以包含到主线内核中。

子系统维护人员每个人都管理着自己版本的内核源代码树,通常(并非总是)使用Git。
Git等工具(以及Quilt或Mercurial等相关工具)允许维护人员跟踪补丁列表,包括作者
信息和其他元数据。在任何给定的时间,维护人员都可以确定他或她的存储库中的哪
些补丁在主线中找不到。

当合并窗口打开时,顶级维护人员将要求Linus从存储库中“拉出”他们为合并选择
的补丁。如果Linus同意,补丁流将流向他的存储库,成为主线内核的一部分。
Linus对拉取中接收到的特定补丁的关注程度各不相同。很明显,有时他看起来很
关注。但是一般来说,Linus相信子系统维护人员不会向上游发送坏补丁。

子系统维护人员反过来也可以从其他维护人员那里获取补丁。例如,网络树是由首先
在专用于网络设备驱动程序、无线网络等的树中积累的补丁构建的。此存储链可以
任意长,但很少超过两个或三个链接。由于链中的每个维护者都信任那些管理较低
级别树的维护者,所以这个过程称为“信任链”。

显然,在这样的系统中,获取内核补丁取决于找到正确的维护者。直接向Linus发送
补丁通常不是正确的方法。

Next 树
-------

子系统树链引导补丁流到内核,但它也提出了一个有趣的问题:如果有人想查看为
下一个合并窗口准备的所有补丁怎么办?开发人员将感兴趣的是,还有什么其他的
更改有待解决,以了解是否存在需要担心的冲突;例如,更改核心内核函数原型的
修补程序将与使用该函数旧形式的任何其他修补程序冲突。审查人员和测试人员希望
在所有这些变更到达主线内核之前,能够访问它们的集成形式的变更。您可以从所有
相关的子系统树中提取更改,但这将是一项复杂且容易出错的工作。

解决方案以-next树的形式出现,在这里子系统树被收集以供测试和审查。这些树中
由Andrew Morton维护的较老的一个,被称为“-mm”(用于内存管理,创建时为此)。
-mm 树集成了一长串子系统树中的补丁;它还包含一些旨在帮助调试的补丁。

除此之外,-mm 还包含大量由Andrew直接选择的补丁。这些补丁可能已经发布在邮件
列表上,或者它们可能应用于内核中未指定子系统树的部分。同时,-mm 作为最后
手段的子系统树;如果没有其他明显的路径可以让补丁进入主线,那么它很可能最
终选择-mm 树。累积在-mm 中的各种补丁最终将被转发到适当的子系统树,或者直接
发送到Linus。在典型的开发周期中,大约5-10%的补丁通过-mm 进入主线。

当前-mm 补丁可在“mmotm”(-mm of the moment)目录中找到:

        https://www.ozlabs.org/~akpm/mmotm/

然而,使用MMOTM树可能会十分令人头疼;它甚至可能无法编译。

下一个周期补丁合并的主要树是linux-next,由Stephen Rothwell 维护。根据设计
linux-next 是下一个合并窗口关闭后主线的快照。linux-next树在Linux-kernel 和
Linux-next 邮件列表中发布,可从以下位置下载:

        https://www.kernel.org/pub/linux/kernel/next/

Linux-next 已经成为内核开发过程中不可或缺的一部分;在一个给定的合并窗口中合并
的所有补丁都应该在合并窗口打开之前的一段时间内找到进入Linux-next 的方法。

Staging 树
----------

内核源代码树包含drivers/staging/目录,其中有许多驱动程序或文件系统的子目录
正在被添加到内核树中。它们在仍然需要更多的修正的时候可以保留在driver/staging/
目录中;一旦完成,就可以将它们移到内核中。这是一种跟踪不符合Linux内核编码或
质量标准的驱动程序的方法,人们可能希望使用它们并跟踪开发。

Greg Kroah Hartman 目前负责维护staging 树。仍需要修正的驱动程序将发送给他,
每个驱动程序在drivers/staging/中都有自己的子目录。除了驱动程序源文件之外,
目录中还应该有一个TODO文件。TODO文件列出了驱动程序需要接受的暂停的工作,
以及驱动程序的任何补丁都应该抄送的人员列表。当前的规则要求,staging的驱动
程序必须至少正确编译。

Staging 是一种让新的驱动程序进入主线的相对容易的方法,它们会幸运地引起其他
开发人员的注意,并迅速改进。然而,进入staging并不是故事的结尾;staging中
没有看到常规进展的代码最终将被删除。经销商也倾向于相对不愿意使用staging驱动
程序。因此,在成为一个合适的主线驱动的路上,staging 仅是一个中转站。

工具
----

从上面的文本可以看出,内核开发过程在很大程度上依赖于在不同方向上聚集补丁的
能力。如果没有适当强大的工具,整个系统将无法在任何地方正常工作。关于如何使用
这些工具的教程远远超出了本文档的范围,但还是用一点篇幅介绍一些关键点。

到目前为止,内核社区使用的主要源代码管理系统是git。Git是在自由软件社区中开发
的许多分布式版本控制系统之一。它非常适合内核开发,因为它在处理大型存储库和
大量补丁时性能非常好。它也以难以学习和使用而著称,尽管随着时间的推移它变得
更好了。对于内核开发人员来说,对Git的某种熟悉几乎是一种要求;即使他们不将它
用于自己的工作,他们也需要Git来跟上其他开发人员(以及主线)正在做的事情。

现在几乎所有的Linux发行版都打包了Git。Git主页位于:

        https://git-scm.com/

此页面包含了文档和教程的链接。

在不使用git的内核开发人员中,最流行的选择几乎肯定是Mercurial:

        http://www.seleric.com/mercurial/

Mercurial与Git共享许多特性,但它提供了一个界面,许多人觉得它更易于使用。

另一个值得了解的工具是Quilt:

        https://savannah.nongnu.org/projects/quilt

Quilt 是一个补丁管理系统,而不是源代码管理系统。它不会随着时间的推移跟踪历史;
相反,它面向根据不断发展的代码库跟踪一组特定的更改。一些主要的子系统维护人员
使用Quilt来管理打算向上游移动的补丁。对于某些树的管理(例如-mm),quilt 是
最好的工具。

邮件列表
--------

大量的Linux内核开发工作是通过邮件列表完成的。如果不加入至少一个某个列表,
就很难成为社区中的一个“全功能”成员。但是,Linux邮件列表对开发人员来说也是
一个潜在的危险,他们可能会被一堆电子邮件淹没、违反Linux列表上使用的约定,
或者两者兼而有之。

大多数内核邮件列表都在vger.kernel.org上运行;主列表位于:

        http://vger.kernel.org/vger-lists.html

不过,也有一些列表托管在别处;其中一些列表位于
redhat.com/mailman/listinfo。

当然,内核开发的核心邮件列表是linux-kernel。这个列表是一个令人生畏的地方:
每天的信息量可以达到500条,噪音很高,谈话技术性很强,且参与者并不总是表现出
高度的礼貌。但是,没有其他地方可以让内核开发社区作为一个整体聚集在一起;
不使用此列表的开发人员将错过重要信息。

以下一些提示可以帮助在linux-kernel生存:

- 将邮件转移到单独的文件夹,而不是主邮箱文件夹。我们必须能够持续地忽略洪流。

- 不要试图跟上每一次谈话——没人会这样。重要的是要筛选感兴趣的主题(但请注意
  长时间的对话可能会偏离原来的主题,尽管未改变电子邮件的主题)和参与的人。

- 不要回复挑事的人。如果有人试图激起愤怒,请忽略他们。

- 当回复Linux内核电子邮件(或其他列表上的电子邮件)时,请为所有相关人员保留
  Cc: 抄送头。如果没有确实的理由(如明确的请求),则不应删除收件人。一定要
  确保你要回复的人在抄送列表中。这个惯例也使你不必在回复邮件时明确要求被抄送。

- 在提出问题之前,搜索列表存档(和整个网络)。有些开发人员可能会对那些显然
  没有完成家庭作业的人感到不耐烦。

- 避免顶部回复(把你的答案放在你要回复的引文上面的做法)。这会让你的回答更难
  理解,印象也很差。

- 在正确的邮件列表发问。linux-kernel 可能是通用的讨论场所,但它不是寻找所有
  子系统开发人员的最佳场所。

最后一点——找到正确的邮件列表——是开发人员常出错的地方。在linux-kernel上
提出与网络相关的问题的人几乎肯定会收到一个礼貌的建议,转到netdev列表上提出,
因为这是大多数网络开发人员经常出现的列表。还有其他列表可用于scsi、video4linux、
ide、filesystem等子系统。查找邮件列表的最佳位置是与内核源代码一起打包的
MAINTAINERS文件。

开始内核开发
------------

关于如何开始内核开发过程的问题很常见——个人和公司皆然。同样常见的是失误,这
使得关系的开始比本应的更困难。

公司通常希望聘请知名的开发人员来启动开发团队。实际上,这是一种有效的技术。
但它也往往是昂贵的,而且对增加有经验的内核开发人员的数量没有多大帮助。考
虑到时间投入,可以让内部开发人员加快Linux内核的开发速度。利用这段时间可以
让雇主拥有一批既了解内核又了解公司的开发人员,还可以帮助培训其他人。从中期
来看,这通常是更有利可图的方法。

可以理解的是,单个开发人员往往对起步感到茫然。从一个大型项目开始可能会很
吓人;人们往往想先用一些较小的东西来试试水。由此,一些开发人员开始创建修补
拼写错误或轻微编码风格问题的补丁。不幸的是,这样的补丁会产生一定程度的噪音,
这会分散整个开发社区的注意力,因此,它们越来越被人不看重。希望向社区介绍
自己的新开发人员将无法通过这些方式获得他们期待的反响。

Andrew Morton 为有抱负的内核开发人员提供了如下建议

::

	所有内核开发者的第一个项目肯定应该是“确保内核在您可以操作的所有
	机器上始终完美运行”。通常的方法是和其他人一起解决问题(这可能需
	要坚持!),但就是如此——这是内核开发的一部分。

(http://lwn.net/Articles/283982/)

在没有明显问题需要解决的情况下,通常建议开发人员查看当前的回归和开放缺陷
列表。从来都不缺少需要解决的问题;通过解决这些问题,开发人员将从该过程获得
经验,同时与开发社区的其他成员建立相互尊重。