openSource 知:回合开源社区补丁

1. 前言

我们在使用开源软件的时候,一般会选定一个目标版本。这个目标版本可能是最新版本、最新稳定版、某个活跃度高的稳定版本、或者其它LTS版本。

我们选定的版本,在使用过程中可能会逐渐的发现一些缺陷,这些缺陷有可能在社区已经修复了,因为社区发布版本后,会继续向前演进(除非停止维护),某些缺陷会在更新的发布版本或开发版本中解决。如果我们要修复这些缺陷,大概有两种途径:一是升级到更新的版本,二是回合开源社区修复这些缺陷的补丁。

版本升级带来的影响可能很大,所以在升级未列入计划的时候,一般会采用回合开源社区补丁的方式来修复缺陷,这种方式就是本文要分析的内容。

2. 回合

回合,是指往回合入或向后移植的意思,英文是backport,并非是指大战三百回合中的回合。向后移植说明是从新到老,在开源软件中,回合一般有两层意思:一是开源社区新版本的修改回合到用户使用的老版本中,二是用户在老版本中开发的新特性或自研修复的缺陷回合到社区的开发版本中。本文要讲的是第一种回合。

2.1. 举例

假设我们使用的开源软件版本是 v1,git提交记录是 abcde(每个字母表示一次提交)。开源社区继续向前演进,git提交记录变成 abcdefghijklmnopq。我们在 v1 版本中遇到了缺陷,发现在 k 对应的提交上解决了,现在我们希望回合 k 提交对应的补丁到我们使用的版本上来解决这个缺陷。

a b c d e
a b c d e f g h i j k l m n o p q
                    ^

2.2. 关键补丁

缺陷情况有很多种,但一般情况下最后都是由某个局部导致的,这个局部可能是一个接口,通过这个接口最终可以确定是哪个文件。再根据这个文件的修订记录(查看方法:git log [options] 文件相对路径)进行分析,有明确说明的缺陷可以很直观的识别到,没有明确说明的往往就需要对每个提交记录做分析,最终确定哪个提交可以解决。

有的缺陷并不是一次提交就能解决的,一般会由某一个关键提交解决,这个关键提交还有一些前置提交。如果关键提交没有彻底解决,还会有一些后置提交,所以只回合 k 的提交往往是不够的。只有把缺陷相关的(直接的、间接的)提交都分析到位,最终回合 k 及其前后置(如果有)提交才能确保缺陷被修复。这也是回合开源社区补丁最复杂,最难搞的地方。

作者称这里的关键提交对应的补丁为关键补丁

2.3. 前置补丁

2.3.1. 直接前置补丁

前面说到缺陷最终会体现到某个文件,那么至少这个文件的修订记录,在 k 之前的应该都是前置补丁。接下来就要分析哪些是缺陷相关的,作者称这些和缺陷相关的前置补丁为直接前置补丁
例如某个缺陷文件 F1 的提交记录为 acefhik,其中 k 的直接前置补丁为 h:

a b c d e
a b c d e f g h i j k l m n o p q

a - c - e f - h i - k (F1)
              ^~~~~~^

2.3.2. 间接前置补丁

可是,要是所有提交都是修改同一个文件,那就太简单了。往往一次提交会修改多个文件,比如 h 对应的提交可能同时修改了文件 F2,其中 F2 的提交记录为 abdgh,如下:

a b c d e
a b c d e f g h i j k l m n o p q

a - c - e f - h i - k (F1)
              ^~~~~~^
a b - d - - g h - - - (F2)
            ^~^

如果 g 对应的提交又同时修改了文件 F2、F3……,理论上我们应该不断的拓扑下去,直到没有新的提交和新增修改文件为止。实际上如果拓扑关系太复杂的话,我们可以在适当的提交处停止拓扑,条件是这些提交跟缺陷没有直接关系,但是,没有直接关系不代表就真没关系了(这种情况就隐藏的比较深,可能被坑),作者称这些拓扑出来的和缺陷相关的前置补丁为间接前置补丁

2.4. 后置补丁

我们找出来的这些关键补丁和前置补丁有时候并不是全部的,因为这些补丁也可能是有缺陷的,所以我们还需要向后去寻找是否有缺陷修复补丁。作者一般是通过这些关键补丁和前置补丁的提交号进行过滤,如果可以过滤出多个,说明有缺陷修复补丁;如果没有过滤出多个,也不代表没有缺陷修复补丁,因为有的软件维护者并不一定会在提交信息中提到修复的提交号,这是一个规范问题,而开源软件往往并不很规范。对于没有过滤出多个提交号的情况,可能会出现漏合,可以参考下面防漏合的措施。

作者称这些修复补丁为后置补丁

2.5. 补丁拓扑

同一个补丁可能修改多个文件,同一个文件可能被多个补丁修改,拓扑的最终结果是,拓扑图内的所有补丁只修改拓扑图内的文件,拓扑图内的所有文件只被拓扑图内的补丁修改。

2.6. 漏合

如前面所讲,如果我们补丁的拓扑未识别完全,比如我们根据分析在适当处停止了拓扑,或者我们分析时排除了不相关的补丁,往往漏合都发生在这种看似无关的地方。因为我们不是开源软件社区维护者,所以哪些有间接关系是很难知道的。

2.6.1. 漏合的影响

1)编译失败
这种影响小,因为可以及时发现并进行解决,不会让影响继续扩散。(需要编译验证充分)
2)高概率执行失败
编译成功往往是第一步,编译成功仅说明语法语义上没问题,不能说明功能没问题,所以要配合相应的测试用例进行测试。这种影响中等,因为只要测试覆盖全,充分测试后也是可以及时发现并解决的,不会让影响继续向下蔓延。(需要测试验证充分)
3)低概率执行失败
万一我们漏分析了一些补丁,或是排除了以为的不相关的补丁,经过自验也没发现什么问题,但是里面可能隐藏着低概率的执行失败情况,这样发出去的软件危险性是很大的,一旦触发问题也是很难定位的,影响也是巨大的。

2.6.2. 防漏合措施

对于低概率执行失败的漏合情况,如果我们往最坏的情况想,带来的后果可能是灾难性的,所以我们应当尽可能的防止这种情况发生,下面是一些作者梳理的措施。
1)输出分析文档
尽可能详细的输出分析过程,至少包括如何分析出关键补丁、直接前置补丁、间接前置补丁、后置补丁以及排除不相干的补丁的原因等。承载分析过程的方式一般是分析文档。
2)充分自验
自验可以及早的识别一些问题,问题发现越早,修复成本越低。自验包括但不限于编译、执行、测试。
3)评审/检视
分析人往往经验是有限的,考虑也不一定是全面的,所以需要相关人等(开发者、测试者等)一并参与,在补丁合入前,进行评审/检视。
4)其它

2.6.3. 漏合的分类

漏合补丁实际上是很难规避的,因为除了要拓扑完补丁,拓扑出来的补丁还要分析清楚,天知道这些补丁改的是什么。对于有很好注释和说明的软件,可能还好些。但有时即便有说明,也读不懂,不是假不懂,是真不懂。在无法避免漏合的情况下,作者梳理了一些大概会漏合哪些种类的补丁。

1)漏合当前缺陷的修复补丁
如果修复当前缺陷的补丁总共有5个,我们最后只识别出来4个,那么漏合的这1个可能就会导致新的问题。这种情况,根据问题现象反推(通过调试等手段推导)引发问题的原因往往是比较难和耗时的,可以结合问题现象重新再做补丁拓扑分析,或者齐头并进。

2)漏合已知其它缺陷的修复补丁
如果我们将当前缺陷的补丁全部合入了,但是模块往往不是孤立的,当前模块很可能用到其它模块的功能。若这个被用的功能有缺陷,在分析补丁的时候,很可能就会被排除。或者因为这个缺陷是已知的,将来触发问题的时候,也会很容易排查出来,所以很有可能会不合(间接漏合)。

缺陷拓扑:一个软件会存在很多缺陷,回合一个缺陷A的补丁时,若这些补丁中新增了一些模块或接口的使用,而这个新增的使用存在缺陷B时,那么当前缺陷A就和这个缺陷B存在了关联,理论上还需要分析这个缺陷B的修复补丁,缺陷B的修复补丁也可能会新增模块或接口的使用,所以缺陷也需要拓扑。

2.7. 工具

补丁分析是一件很繁琐的过程,一般人往往都不愿意做补丁拓扑,所以也给漏合带来了很大的风险,作者这里提供一些工具方法,可以用来辅助补丁拓扑。

还是以上文举的例子来看,假设文件Fx的修订记录为 bcgjk,如下所示:

a b c d e
a b c d e f g h i j k l m n o p q
- b c - - - g - - j k --- (Fx)
            ^~~~~~^~^
          ^~^~~~~~^~^

文件Fx修订记录,社区新版本比用户使用版本增加了 gjk 三个提交,这时候至少我们需要分析 g->k 之间所有提交对应的补丁,有可能 g 提交也有前置补丁,所以我们还要分析 g 之前的社区新版本中的提交。

2.7.1. 生成补丁

可以使用如下命令生成补丁:

git format-patch <revision range>

通过按范围 c..k 来生成补丁,不包含c,defghijk对应的补丁都会生成,两个版本的对比,实际多生成了de 对应的补丁,所以我们应该按范围 e..k 来生成补丁,如下:

git format-patch e..k

假设e和k都是提交号。

细心的读者可能已经发现了,实际上生成的补丁就是用户使用的版本提交号到关键补丁对应提交号之间的所有补丁,即关键补丁及之前所有新于用户使用版本的补丁。对于活跃度高、版本跨度大的软件,这些补丁数量可能达到几百上千,所以往往是拓扑不完的,即便能拓扑完也很难分析完……

2.7.2. 分组补丁

实际上我们应该做 f->k 范围的补丁拓扑,上述先生成补丁,是为了我们工具化去做补丁拓扑,一个拓扑图对一个补丁组。参考工具如下:

仓库:https://gitee.com/maminjie/ola
分支:develop
用法:

bash ola.sh pat g DIR

举例:
在这里插入图片描述
ola仓库中提供了patcher.py脚本,可以单独使用,仅供参考。

3. 后语

补丁就像螺丝钉,少了一个,火箭可能就无法升空了,请重视它!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值