361 lines
20 KiB
ReStructuredText
361 lines
20 KiB
ReStructuredText
|
.. include:: ../disclaimer-zh_CN.rst
|
|||
|
|
|||
|
:Original: :ref:`Documentation/process/2.Process.rst <development_process>`
|
|||
|
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
|
|||
|
|
|||
|
.. _cn_development_process:
|
|||
|
|
|||
|
开发流程如何工作
|
|||
|
================
|
|||
|
|
|||
|
90年代早期的Linux内核开发是一件相当松散的事情,涉及的用户和开发人员相对较
|
|||
|
少。由于拥有数以百万计的用户群,并且在一年的时间里有大约2000名开发人员参与
|
|||
|
进来,内核因此必须发展许多流程来保持开发的顺利进行。要成为流程的有效组成
|
|||
|
部分,需要对流程的工作方式有一个扎实的理解。
|
|||
|
|
|||
|
总览
|
|||
|
----
|
|||
|
|
|||
|
内核开发人员使用一个松散的基于时间的发布过程,每两到三个月发布一次新的主要
|
|||
|
内核版本。最近的发布历史记录如下:
|
|||
|
|
|||
|
====== =================
|
|||
|
4.11 四月 30, 2017
|
|||
|
4.12 七月 2, 2017
|
|||
|
4.13 九月 3, 2017
|
|||
|
4.14 十一月 12, 2017
|
|||
|
4.15 一月 28, 2018
|
|||
|
4.16 四月 1, 2018
|
|||
|
====== =================
|
|||
|
|
|||
|
每4.x版本都是一个主要的内核版本,具有新特性、内部API更改等等。一个典型的4.x
|
|||
|
版本包含大约13000个变更集,变更了几十万行代码。因此,4.x是Linux内核开发的前
|
|||
|
沿;内核使用滚动开发模型,不断集成重大变化。
|
|||
|
|
|||
|
对于每个版本的补丁合并,遵循一个相对简单的规则。在每个开发周期的开始,“合并
|
|||
|
窗口”被打开。当时,被认为足够稳定(并且被开发社区接受)的代码被合并到主线内
|
|||
|
核中。在这段时间内,新开发周期的大部分变更(以及所有主要变更)将以接近每天
|
|||
|
1000次变更(“补丁”或“变更集”)的速度合并。
|
|||
|
|
|||
|
(顺便说一句,值得注意的是,合并窗口期间集成的更改并不是凭空产生的;它们是
|
|||
|
提前收集、测试和分级的。稍后将详细描述该过程的工作方式)。
|
|||
|
|
|||
|
合并窗口持续大约两周。在这段时间结束时,LinusTorvalds将声明窗口已关闭,并
|
|||
|
释放第一个“rc”内核。例如,对于目标为4.14的内核,在合并窗口结束时发生的释放
|
|||
|
将被称为4.14-rc1。RC1版本是一个信号,表示合并新特性的时间已经过去,稳定下一
|
|||
|
个内核的时间已经开始。
|
|||
|
|
|||
|
在接下来的6到10周内,只有修复问题的补丁才应该提交给主线。有时会允许更大的
|
|||
|
更改,但这种情况很少发生;试图在合并窗口外合并新功能的开发人员往往会受到不
|
|||
|
友好的接待。一般来说,如果您错过了给定特性的合并窗口,最好的做法是等待下一
|
|||
|
个开发周期。(对于以前不支持的硬件,偶尔会对驱动程序进行例外;如果它们不
|
|||
|
改变已有代码,则不会导致回归,并且应该可以随时安全地添加)。
|
|||
|
|
|||
|
随着修复程序进入主线,补丁速度将随着时间的推移而变慢。Linus大约每周发布一次
|
|||
|
新的-rc内核;一个正常的系列将在-rc6和-rc9之间,内核被认为足够稳定并最终发布。
|
|||
|
然后,整个过程又重新开始了。
|
|||
|
|
|||
|
例如,这里是4.16的开发周期进行情况(2018年的所有日期):
|
|||
|
|
|||
|
============== ==============================
|
|||
|
一月 28 4.15 稳定版发布
|
|||
|
二月 11 4.16-rc1, 合并窗口关闭
|
|||
|
二月 18 4.16-rc2
|
|||
|
二月 25 4.16-rc3
|
|||
|
三月 4 4.16-rc4
|
|||
|
三月 11 4.16-rc5
|
|||
|
三月 18 4.16-rc6
|
|||
|
三月 25 4.16-rc7
|
|||
|
四月 1 4.16 稳定版发布
|
|||
|
============== ==============================
|
|||
|
|
|||
|
开发人员如何决定何时结束开发周期并创建稳定的版本?使用的最重要的指标是以前
|
|||
|
版本的回归列表。不欢迎出现任何错误,但是那些破坏了以前能工作的系统的错误被
|
|||
|
认为是特别严重的。因此,导致回归的补丁是不受欢迎的,很可能在稳定期内删除。
|
|||
|
|
|||
|
开发人员的目标是在稳定发布之前修复所有已知的回归。在现实世界中,这种完美是
|
|||
|
很难实现的;在这种规模的项目中,变量太多了。有一点,延迟最终版本只会使问题
|
|||
|
变得更糟;等待下一个合并窗口的一堆更改将变大,从而在下次创建更多的回归错误。
|
|||
|
因此,大多数4.x内核都有一些已知的回归错误,不过,希望没有一个是严重的。
|
|||
|
|
|||
|
一旦一个稳定的版本发布,它正在进行的维护工作就被移交给“稳定团队”,目前由
|
|||
|
Greg Kroah-Hartman组成。稳定团队将使用4.x.y编号方案不定期的发布稳定版本的更
|
|||
|
新。要加入更新版本,补丁程序必须(1)修复一个重要的bug,(2)已经合并到
|
|||
|
下一个开发主线中。内核通常会在超过其初始版本的一个以上的开发周期内接收稳定
|
|||
|
的更新。例如,4.13内核的历史如下
|
|||
|
|
|||
|
============== ===============================
|
|||
|
九月 3 4.13 稳定版发布
|
|||
|
九月 13 4.13.1
|
|||
|
九月 20 4.13.2
|
|||
|
九月 27 4.13.3
|
|||
|
十月 5 4.13.4
|
|||
|
十月 12 4.13.5
|
|||
|
... ...
|
|||
|
十一月 24 4.13.16
|
|||
|
============== ===============================
|
|||
|
|
|||
|
4.13.16是4.13版本的最终稳定更新。
|
|||
|
|
|||
|
有些内核被指定为“长期”内核;它们将得到更长时间的支持。在本文中,当前的长期
|
|||
|
内核及其维护者是:
|
|||
|
|
|||
|
====== ====================== ==============================
|
|||
|
3.16 Ben Hutchings (长期稳定内核)
|
|||
|
4.1 Sasha Levin
|
|||
|
4.4 Greg Kroah-Hartman (长期稳定内核)
|
|||
|
4.9 Greg Kroah-Hartman
|
|||
|
4.14 Greg Kroah-Hartman
|
|||
|
====== ====================== ==============================
|
|||
|
|
|||
|
为长期支持选择内核纯粹是维护人员有必要和时间来维护该版本的问题。目前还没有
|
|||
|
为即将发布的任何特定版本提供长期支持的已知计划。
|
|||
|
|
|||
|
补丁的生命周期
|
|||
|
--------------
|
|||
|
|
|||
|
补丁不会直接从开发人员的键盘进入主线内核。相反,有一个稍微复杂(如果有些非
|
|||
|
正式)的过程,旨在确保对每个补丁进行质量审查,并确保每个补丁实现了一个在主线
|
|||
|
中需要的更改。对于小的修复,这个过程可能会很快发生,或者,在大的和有争议的
|
|||
|
变更的情况下,会持续数年。许多开发人员的挫折来自于对这个过程缺乏理解或者
|
|||
|
试图绕过它。
|
|||
|
|
|||
|
为了减少这种挫折感,本文将描述补丁如何进入内核。下面是一个介绍,它以某种
|
|||
|
理想化的方式描述了这个过程。更详细的过程将在后面的章节中介绍。
|
|||
|
|
|||
|
补丁程序经历的阶段通常是:
|
|||
|
|
|||
|
- 设计。这就是补丁的真正需求——以及满足这些需求的方式——的所在。设计工作通常
|
|||
|
是在不涉及社区的情况下完成的,但是如果可能的话,最好是在公开的情况下完成
|
|||
|
这项工作;这样可以节省很多稍后再重新设计的时间。
|
|||
|
|
|||
|
- 早期评审。补丁被发布到相关的邮件列表中,列表中的开发人员会回复他们可能有
|
|||
|
的任何评论。如果一切顺利的话,这个过程应该会发现补丁的任何主要问题。
|
|||
|
|
|||
|
- 更广泛的评审。当补丁接近准备好纳入主线时,它应该被相关的子系统维护人员
|
|||
|
接受——尽管这种接受并不能保证补丁会一直延伸到主线。补丁将出现在维护人员的
|
|||
|
子系统树中,并进入 -next 树(如下所述)。当流程工作时,此步骤将导致对补丁
|
|||
|
进行更广泛的审查,并发现由于将此补丁与其他人所做的工作集成而导致的任何
|
|||
|
问题。
|
|||
|
|
|||
|
- 请注意,大多数维护人员也有日常工作,因此合并补丁可能不是他们的最高优先级。
|
|||
|
如果您的补丁程序得到了关于所需更改的反馈,那么您应该进行这些更改,或者为
|
|||
|
不应该进行这些更改的原因辩护。如果您的补丁没有评审意见,但没有被其相应的
|
|||
|
子系统或驱动程序维护者接受,那么您应该坚持不懈地将补丁更新到当前内核,使
|
|||
|
其干净地应用,并不断地将其发送以供审查和合并。
|
|||
|
|
|||
|
- 合并到主线。最终,一个成功的补丁将被合并到由LinusTorvalds管理的主线存储库
|
|||
|
中。此时可能会出现更多的评论和/或问题;开发人员应对这些问题并解决出现的
|
|||
|
任何问题很重要。
|
|||
|
|
|||
|
- 稳定版发布。可能受补丁影响的用户数量现在很大,因此可能再次出现新的问题。
|
|||
|
|
|||
|
- 长期维护。虽然开发人员在合并代码后可能会忘记代码,但这种行为往往会给开发
|
|||
|
社区留下不良印象。合并代码消除了一些维护负担,因为其他代码将修复由API
|
|||
|
更改引起的问题。但是,如果代码要长期保持有用,原始开发人员应该继续为
|
|||
|
代码负责。
|
|||
|
|
|||
|
内核开发人员(或他们的雇主)犯的最大错误之一是试图将流程简化为一个
|
|||
|
“合并到主线”步骤。这种方法总是会让所有相关人员感到沮丧。
|
|||
|
|
|||
|
补丁如何进入内核
|
|||
|
----------------
|
|||
|
|
|||
|
只有一个人可以将补丁合并到主线内核存储库中:LinusTorvalds。但是,在进入
|
|||
|
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)目录中找到,地址:
|
|||
|
|
|||
|
http://www.ozlabs.org/~akpm/mmotm/
|
|||
|
|
|||
|
然而,使用mmotm树可能是一种令人沮丧的体验;它甚至可能无法编译。
|
|||
|
|
|||
|
下一个周期补丁合并的主要树是linux-next,由Stephen Rothwell 维护。根据设计
|
|||
|
linux-next 是下一个合并窗口关闭后主线的快照。linux-next树在Linux-kernel 和
|
|||
|
Linux-next 邮件列表中发布,可从以下位置下载:
|
|||
|
|
|||
|
http://www.kernel.org/pub/linux/kernel/next/
|
|||
|
|
|||
|
Linux-next 已经成为内核开发过程中不可或缺的一部分;在一个给定的合并窗口中合并
|
|||
|
的所有补丁都应该在合并窗口打开之前的一段时间内找到进入Linux-next 的方法。
|
|||
|
|
|||
|
Staging 树
|
|||
|
----------
|
|||
|
|
|||
|
内核源代码树包含drivers/staging/directory,其中有许多驱动程序或文件系统的
|
|||
|
子目录正在被添加到内核树中。它们然需要更多的工作的时候可以保留在
|
|||
|
driver/staging目录中;一旦完成,就可以将它们移到内核中。这是一种跟踪不符合
|
|||
|
Linux内核编码或质量标准的驱动程序的方法,但人们可能希望使用它们并跟踪开发。
|
|||
|
|
|||
|
Greg Kroah Hartman 目前负责维护staging 树。仍需要工作的驱动程序将发送给他,
|
|||
|
每个驱动程序在drivers/staging/中都有自己的子目录。除了驱动程序源文件之外,
|
|||
|
目录中还应该有一个TODO文件。todo文件列出了驱动程序需要接受的挂起的工作,
|
|||
|
以及驱动程序的任何补丁都应该抄送的人员列表。当前的规则要求,staging的驱动
|
|||
|
程序必须至少正确编译。
|
|||
|
|
|||
|
Staging 是一种相对容易的方法,可以让新的驱动程序进入主线,幸运的是,他们会
|
|||
|
引起其他开发人员的注意,并迅速改进。然而,进入staging并不是故事的结尾;
|
|||
|
staging中没有看到常规进展的代码最终将被删除。经销商也倾向于相对不愿意使用
|
|||
|
staging驱动程序。因此,在成为一名合适的主线驱动的路上,staging 充其量只是
|
|||
|
一个停留。
|
|||
|
|
|||
|
工具
|
|||
|
----
|
|||
|
|
|||
|
从上面的文本可以看出,内核开发过程在很大程度上依赖于在不同方向上聚集补丁的
|
|||
|
能力。如果没有适当强大的工具,整个系统将无法在任何地方正常工作。关于如何使用
|
|||
|
这些工具的教程远远超出了本文档的范围,但是还是有一些指南的空间。
|
|||
|
|
|||
|
到目前为止,内核社区使用的主要源代码管理系统是git。Git是在自由软件社区中开发
|
|||
|
的许多分布式版本控制系统之一。它非常适合内核开发,因为它在处理大型存储库和
|
|||
|
大量补丁时性能非常好。它还有一个难以学习和使用的名声,尽管随着时间的推移它
|
|||
|
变得更好了。对于内核开发人员来说,对Git的某种熟悉几乎是一种要求;即使他们不
|
|||
|
将它用于自己的工作,他们也需要Git来跟上其他开发人员(以及主线)正在做的事情。
|
|||
|
|
|||
|
现在几乎所有的Linux发行版都打包了Git。主页位于:
|
|||
|
|
|||
|
http://git-scm.com/
|
|||
|
|
|||
|
那个页面有指向文档和教程的指针。
|
|||
|
|
|||
|
在不使用git的内核开发人员中,最流行的选择几乎肯定是mercurial:
|
|||
|
|
|||
|
http://www.seleric.com/mercurial/
|
|||
|
|
|||
|
Mercurial与Git共享许多特性,但它提供了一个界面,许多人觉得它更易于使用。
|
|||
|
|
|||
|
另一个值得了解的工具是quilt:
|
|||
|
|
|||
|
http://savannah.nongnu.org/projects/quilt
|
|||
|
|
|||
|
Quilt 是一个补丁管理系统,而不是源代码管理系统。它不会随着时间的推移跟踪历史;
|
|||
|
相反,它面向根据不断发展的代码库跟踪一组特定的更改。一些主要的子系统维护人员
|
|||
|
使用Quilt来管理打算向上游移动的补丁。对于某些树的管理(例如-mm),quilt 是
|
|||
|
最好的工具。
|
|||
|
|
|||
|
邮件列表
|
|||
|
--------
|
|||
|
|
|||
|
大量的Linux内核开发工作是通过邮件列表完成的。如果不在某个地方加入至少一个列表,
|
|||
|
就很难成为社区中一个功能完备的成员。但是,Linux邮件列表对开发人员来说也是一个
|
|||
|
潜在的危险,他们可能会被一堆电子邮件淹没,违反Linux列表上使用的约定,或者
|
|||
|
两者兼而有之。
|
|||
|
|
|||
|
大多数内核邮件列表都在vger.kernel.org上运行;主列表位于:
|
|||
|
|
|||
|
http://vger.kernel.org/vger-lists.html
|
|||
|
|
|||
|
不过,也有一些列表托管在别处;其中一些列表位于lists.redhat.com。
|
|||
|
|
|||
|
当然,内核开发的核心邮件列表是linux-kernel。这个名单是一个令人生畏的地方;
|
|||
|
每天的信息量可以达到500条,噪音很高,谈话技术性很强,参与者并不总是表现出
|
|||
|
高度的礼貌。但是,没有其他地方可以让内核开发社区作为一个整体聚集在一起;
|
|||
|
避免使用此列表的开发人员将错过重要信息。
|
|||
|
|
|||
|
有一些提示可以帮助在linux-kernel生存:
|
|||
|
|
|||
|
- 将邮件转移到单独的文件夹,而不是主邮箱。我们必须能够持续地忽略洪流。
|
|||
|
|
|||
|
- 不要试图跟踪每一次谈话-其他人都不会。重要的是要对感兴趣的主题(尽管请
|
|||
|
注意,长时间的对话可以在不更改电子邮件主题行的情况下偏离原始主题)和参与
|
|||
|
的人进行筛选。
|
|||
|
|
|||
|
- 不要挑事。如果有人试图激起愤怒的反应,忽略他们。
|
|||
|
|
|||
|
- 当响应Linux内核电子邮件(或其他列表上的电子邮件)时,请为所有相关人员保留
|
|||
|
cc:header。如果没有强有力的理由(如明确的请求),则不应删除收件人。一定要
|
|||
|
确保你要回复的人在cc:list中。这个惯例也使你不必在回复邮件时明确要求被抄送。
|
|||
|
|
|||
|
- 在提出问题之前,搜索列表档案(和整个网络)。有些开发人员可能会对那些显然
|
|||
|
没有完成家庭作业的人感到不耐烦。
|
|||
|
|
|||
|
- 避免贴顶帖(把你的答案放在你要回复的引文上面的做法)。这会让你的回答更难
|
|||
|
理解,印象也很差。
|
|||
|
|
|||
|
- 询问正确的邮件列表。linux-kernel 可能是通用的讨论点,但它不是从所有子系统
|
|||
|
中寻找开发人员的最佳场所。
|
|||
|
|
|||
|
最后一点——找到正确的邮件列表——是开发人员出错的常见地方。在Linux内核上提出与
|
|||
|
网络相关的问题的人几乎肯定会收到一个礼貌的建议,转而在netdev列表上提出,
|
|||
|
因为这是大多数网络开发人员经常出现的列表。还有其他列表可用于scsi、
|
|||
|
video4linux、ide、filesystem等子系统。查找邮件列表的最佳位置是与内核源代码
|
|||
|
一起打包的MAINTAINERS文件。
|
|||
|
|
|||
|
开始内核开发
|
|||
|
------------
|
|||
|
|
|||
|
关于如何开始内核开发过程的问题很常见——来自个人和公司。同样常见的是错误,这
|
|||
|
使得关系的开始比必须的更困难。
|
|||
|
|
|||
|
公司通常希望聘请知名的开发人员来启动开发团队。实际上,这是一种有效的技术。
|
|||
|
但它也往往是昂贵的,而且没有增长经验丰富的内核开发人员储备。考虑到时间的
|
|||
|
投入,可以让内部开发人员加快Linux内核的开发速度。花这个时间可以让雇主拥有
|
|||
|
一批了解内核和公司的开发人员,他们也可以帮助培训其他人。从中期来看,这往往
|
|||
|
是更有利可图的方法。
|
|||
|
|
|||
|
可以理解的是,单个开发人员往往对起步感到茫然。从一个大型项目开始可能会很
|
|||
|
吓人;人们往往想先用一些较小的东西来测试水域。这是一些开发人员开始创建修补
|
|||
|
拼写错误或轻微编码风格问题的补丁的地方。不幸的是,这样的补丁会产生一定程度
|
|||
|
的噪音,这会分散整个开发社区的注意力,因此,越来越多的人看不起它们。希望向
|
|||
|
社区介绍自己的新开发人员将无法通过这些方式获得他们想要的那种接待。
|
|||
|
|
|||
|
Andrew Morton 为有抱负的内核开发人员提供了这个建议
|
|||
|
|
|||
|
::
|
|||
|
|
|||
|
所有内核初学者的No.1项目肯定是“确保内核在所有的机器上,你可以触摸
|
|||
|
到的,始终运行良好" 通常这样做的方法是与其他人一起解决问题(这
|
|||
|
可能需要坚持!)但这很好——这是内核开发的一部分
|
|||
|
|
|||
|
(http://lwn.net/articles/283982/)
|
|||
|
|
|||
|
在没有明显问题需要解决的情况下,建议开发人员查看当前的回归和开放式错误列表.
|
|||
|
解决需要修复的问题没有任何缺点;通过解决这些问题,开发人员将获得处理过程的
|
|||
|
经验,同时与开发社区的其他人建立尊重。
|