Chapter 7. 打包、发布和日常开发

Table of Contents

版本号
版本号组成部分
简单策略
奇偶数策略
发布分支
发布分支的技巧
稳定发布版本
发布所有者独裁
变更表决
管理协作发布稳定化
发布经理
打包
格式
命名和布局
大写还是不大写
预发布
编译和安装
二进制包
测试和发布
候选发布
宣告发布
维护多发布线
安全发布
发布和日常开发
计划发布

本章关于自由软件项目如何打包和发布软件,以及如何让整个开发模式的组织围绕这个目标。

开源项目和私有项目的主要区别是缺乏对开发团队的中央管理。当准备新版本时,这个区别尤其明显:一个公司可以让整个开发团队集中精力在即将发生的版本上,而将新特性开发和不重要的bug修正放在一边。志愿团队不会如此整齐划一。人们因为各种各样的原因为项目工作,总有些人会对发布版本不感兴趣,会希望在发布时继续常规的开发工作。因为开发不会结束,开源的发布流程很容易变长,但不会如商业发布流程那样分裂。这就像修理高速路。有两种修理方法:你可以将其完全关闭,这样船员们可以全力投入,直到问题被解决,或者你可以在多个小道上同时工作,而让其他人可以自由通行。第一种方法对修理船员非常有效率,但对于其他人来说—完成任务前道路被完全关闭。第二种方法,修理船员(现在他们需要与较少)会需要更长的时间,但至少道路保持可用,尽管不能完全畅通。

开源项目通常会使用第二种方法。实际上,对于同时拥有多条版本线的成熟软件,项目一直处于修理小路的状态。总会有些小道会被关闭;一直存在的但是较低级别的不便能够被整个开发团队容忍,所以才能够有规律的计划发布版本。

这个模型不仅仅能用于版本发布。其原理是并行任务并不是互相依赖的—这并不是只存在于开源项目的原理,但开源项目使用了自己的方法实现了它。他们不能承受对修路工队员或常规交通的过度打扰,同样也不能承受让人们只是站在黄线以外,等待交通疏导。因而,他们会向平缓的、稳定管理负担的过程发展,而不会是充满更多的山谷和高峰。志愿者通常会希望工作中只有一些虽然持续但不太严重的不便;提供些许他们可预测性会让他们可以自由的安排自己的日程,无需担心在项目中发生冲突。但是,如果项目主日程中有些活动会排除其他活动,就会导致很多开发者停止很长时间—不仅非常没有效率,也非常无聊,因而会很危险,因为无聊的开发者会很快变成前开发者。

版本发布工作实际上是并行开发中最容易被注意到的非开发任务,所以下面章节中描述的方法主要针对如何允许发布。然而,也有其他的并行任务,例如翻译和国际化、在整个代码的基础上逐渐扩大API变更等。

版本号

在我们讨论如何发布之前,首先看一下如何命名版本,用户需要从版本中知道什么。一个版本发布意味着:

  • 老的bug被修正了。恐怕所有的用户都认为每个版本都理所当然应该做到这一点。

  • 会带来新bug。一般情况下这是必然的,除非是安全版本或其他特殊情况(见本章后面the section called “安全发布”)。

  • 也加入了新的特性。

  • 新配置选项也会被添加,或者一些以前的选项有了微妙的变化。和上个版本相比,安装步骤可能有轻微的调整,即使人们不希望这样。

  • 也可能带来不兼容的变化,例如以前版本的软件所用的数据格式必须做出某种(可能是手工的)单向的转化,才能继续使用。

就像你看到的,发生的不都是好事。这就是为什么经验丰富的用户总是对新版本保持恐惧,特别是当软件已经足够成熟,已经能够满足他们的需要时(或者认为他们满足了)。即使新特性是好坏参半的事情,也意味着软件现在可能以不可预期的方式运行。

因此发布版本编号的目的是双重的:很明显这个编号可以在交流中明确发布的顺序(例如,通过比较两个版本号,你可以看出哪个版本更老),另一方面,也应该尽可能紧凑的表明该发布所带来变更的程度和性质。

仅仅是号码吗?或多或少是。版本编号策略是最古老的自行车库讨论(见Chapter 6, 交流the section called “主题越软,辩论越长”),这个世界也似乎从来没有能达成一个单独的完整的标准。然而,还是出现了一些好的策略,依据了一些广泛认同的原理:一致性。采取一种编号方式,记录下来,并坚持使用。你的用户会感激不尽。

版本号组成部分

本小节详细描述了一些发布版本号的正式惯例,认为是已知的预先知识。目的仅仅是作为一个参考。如果你已经了解了这些惯例,你可以跳过本小节。

发布号码是一组点分割的数字:

Scanley 2.3
Singer 5.11.4

...等等。这些点不是小数点,而仅仅是分隔符;“5.3.9”之后将会是“5.3.10”。某些项目偶尔也会用其他的提示,例如非常有名的Linux内核,在Linux 1.0之前使用的是“0.95”、“0.96”... “0.99”,但是这种点号成为了固有的习惯,已经被认为是一种标准。数字部分(不包含点的数字部分)的数量没有限制,但是大多数项目不应该超过3或4。在后面我们会对原因有更清楚的认识。

除了数字部分之外,一些项目也会附加一个描述标签,例如“Alpha”或“Beta”(见Alpha和Beta),例如:

Scanley 2.3.0 (Alpha)
Singer 5.11.4 (Beta)

Alpha或Beta修饰意味着这个版本是一个将要发布版本(同样的版本号,但没有修饰)的先例。因此,“2.3.0 (Alpha)”将会带来“2.3.0”。为了能排列好多个这样的候选版本,修饰符也可以有一个之后的修饰。例如,下面是一系列即将发布的版本,根据发布时间排序:

Scanley 2.3.0 (Alpha 1)
Scanley 2.3.0 (Alpha 2)
Scanley 2.3.0 (Beta 1)
Scanley 2.3.0 (Beta 2)
Scanley 2.3.0 (Beta 3)
Scanley 2.3.0

请注意当使用“Alpha”修饰符时,Scanley的"2.3"写作"2.3.0"。这两个号码是等同的—出于简短的目的,结尾所有的0都可以丢掉—但是当有修饰词时,简短成为无需考虑的问题,所以人们会选择完整的方式。

另外一些半正规的修饰词包括“Stable”、“Unstable”、“Development”和“RC”(“发布候选”)。最常用的还是“Alpha”和“Beta”,而“RC”用于第三方,但是请注意“RC”总会包含一个数字修饰。也就是不要使用“Scanley 2.3.0 (RC)”,而使用“Scanley 2.3.0 (RC 1)”,然后是RC2,以此类推。

“Alpha”、“Beta”和“RC”都是已经广为人知的标签了,所以我不建议你使用其他标签,即使是那些乍看起来更常见而非方言的词汇,似乎是更好的选择。但是那些从发布包安装软件的人对于这三个词汇已经非常熟悉,没有理由选择特立独行。

尽管发布版本号码中的点数并不是小数点,但也是起到了位置标示的作用。所有的“0.X.Y”早于“1.0”(等同于“1.0.0”)。“3.14.158”是“3.14.159”直接前继版本,而“3.14.160”和“3.15.任意数”则是“3.14.158”的后继版本,担不是直接后继。

一致的发布版本号码策略可以让用户仅仅从某个软件的版本号就可以判断出版本的重要程度。在一个三部分的系统中,第一部分是主 版本号,第二部分是次 版本号码,而第三部分是小 版本号码。例如版本“2.10.17”是主版本2系列的次要版本10开发线的小版本17。词汇“开发线”和“系列”在这里并不正式,但他们代表了人们期望的含义。一个主系列仅仅是共享同一个主号码的版本,而次要系列(或次要开发线)则由相同次要主号码的版本。也就是说,“2.4.0”和“3.4.1”并不是位于同一个次要系列,即使他们都有次要版本号码4。另一个情况下,“2.4.0”和“2.4.2”则位于同一个次要开发线,尽管他们并不是相邻的版本,因为“2.4.1”版本位于他们之间。

这些号码的含义可以是你自己所期望的:主号码的变更表示发生了主要的变化;次要号码的变化表示发生了次要的变更。有一些项目会有第4部分,通常叫做补丁 号码,特别是一些对区别进行细致控制的项目(有一点让人混淆的是,一些项目将三部分系统中的“微(micro)”版本作为“补丁”。)。也有一些项目使用最后一部分作为构建 号码,随着项目的每一次构建递增,代表了每次变更的变化。这样帮助了项目将每个bug报告与特定构建联系起来,特别是当二进制发布包是发布默认方法时特别有用。

尽管对于使用多少个部分,每个部分的含义有许多不同的习惯,区别通常很小—你会受到一些压力,但是不会太大。下面两小节讨论了最常用的几个习惯。

简单策略

如果仅仅会改变微小版本号码,大多数项目对于将何种变更纳入到发布中会有一些规则,改变主要版本号码则也会有相应的规则。没有这些规则的标准集合,但下面描述是已经在许多项目广泛使用的的政策。你或许会在自己的项目中采用这些方法,但即使不使用,这仍是发布号码所应传达信息的好案例。这个政策是APR项目使用的编号系统,请看http://apr.apache.org/versioning.html

  1. 对于微小号码的变更(也就是在同一个次要开发线上发生的变化)只能是向前和向后兼容的。也就是说,变更只能是bug修正,或仅仅是对现有特性较小的改进。新特性一定不能在微小版本发布中引入。

  2. 次要版本号码(也就是位于同一个主开发线)的变更必须是向前兼容,但不必向后兼容。在次要版本中引入新特性非常常见,但是通常不要一次包含过多特性。

  3. 主版本号码的变更标识了兼容性的边界。新的主版本发布不必向前和向后兼容。新的主版本发布应该包含新的特性,甚至完全的新特性集合。

向后兼容向前兼容的含义取决于你的软件,但通常无需明确的解释。例如,如果你的项目是客户端/服务器应用,那么“向后兼容”意味着将服务器升级到2.6.0不会导致2.5.4的客户端失效,或者工作方式发生变化(当然要排除修正的bug)。另一方面,将客户端升级到2.6.0,可以让客户端享受2.5.4无法使用功能。如果不能做到这一点,则升级不是“向前兼容”:显然,你现在不能将客户端降级到2.5.4,并保持2.6.0的功能,因为一些功能是2.6.0新增的。

这也是微小版本主要用于bug修正的原因。一定要保持双向的兼容性:如果你从2.5.3升级到2.5.4,然后改变主意降级到2.5.3也不会有任何功能损失。当然,2.5.4中修正的bug会再次出现,但不会损失任何新特性,只是bug可能会妨碍现有特性的使用。

客户端/服务器协议仅仅是许多可能的兼容性领域的一种情况。另一种是数据格式:软件会将数据写入永久存储吗?如果是,则数据的写入和读取必须依照发布号码政策所承诺的兼容性方针。版本2.6.0需要能够读取2.5.4写的文件,但是可能会暗自将格式升级到2.5.4无法阅读的新格式,因为跨次要版本边界的无需有降级的能力。如果其他程序使用你的项目发布的代码库,则API也是需要考虑的兼容性领域:你必须确保明确说明源代码和二进制兼容性规则,用户无需担心直接升级是否安全。她应当可以通过版本号码立刻知道结果。

在这个系统中,只有增加主版本号码时你才能从头开始。这确实有些不便:也许你会希望增加某些特性,希望重新设计协议,但是为了维护兼容性而无法实现。这个问题没有魔法解决方案,除非你能在一开始就以可扩展的方式进行设计(值得用单独一本书讨论的主题,当然超出了本书的范围)。但是通过公布发布兼容性政策,并遵守它,是发布软件不能回避的一部分。某个低劣的惊奇只会疏远许多用户。刚刚描述的政策能起到的作用有限,因为它已经广泛传播,但是因为它易于解释和记忆,所以不熟悉的人也可以很快接受。

也需要知道上述规则并不适用于pre-1.0的版本(尽管您的发布政策应当明确陈述,只是要说清楚)。一个还处于初始发布状态的开发可以发布0.1、0.2、0.3以及依次的后续版本,直到1.0,这些发布之间的区别可以任意大。pre-1.0版本的微小版本号可以省略。取决于项目的特性和版本的区别,你或许会发现0.1.0、0.1.1也很有效。pre-1.0的版本号码规则通常比较松散,主要是因为人们明白在项目初期,较强的兼容性限制会严重阻碍开发,而且较早的使用者也较能够容忍这种变化。

请牢记所有这些指令仅适用于三部分系统。你的项目可以轻易的得到不同的三部分系统,甚至可以决定不使用这么细致的粒度,而仅仅使用两部分系统。重要的是要尽早决定,仅按照每个部分的含义发布,并坚持下去。

奇偶数策略

一些项目使用次要版本号码部分表示项目的稳定程度:偶数表示稳定,奇数表示不稳定。仅适用于次要版本号码,不能用于主版本号码和微小版本号码。微小版本号码依然表示bug修正(没有新特性),主版本号码的递增依然表示重大变更,新特性集合。

奇偶系统优势在于它已经被Linux内核项目使用,它提供了一种方法,可以发布新功能用于测试,而无需让产品用户受到潜在不稳定代码的影响。人们在看到“2.4.21”时可以认为能够用于他们使用的web服务器,但当看到“2.5.1”时,则可以用于家用工作站的实验中。开发团队掌握了来自不稳定(奇数次要版本号码)系列的bug报告,当在该系列的一些微小版本中完成了许多工作后,他们便增加次要版本号码(变成偶数),将微小版本号码恢复到“0”,并发布推定的稳定包。

这个系统保留了前面给定的兼容性政策,或至少没有发生冲突。仅仅是在次要版本号码上重载了一些额外的信息。仅仅是让需要的人每次需要增加两个次要版本号码,并没有重大的损害。奇偶系统通常最适合用于拥有较长发布周期的项目,以及因为本性上就需要较高比例的保留用户能为新特性评估稳定性的项目。当然这不是让新功能得以测试的唯一方法,本章后面的章节the section called “稳定发布版本”描述了另一个方法,也是更常见的公布不稳定代码的方法,直接通过发布名称的标识让人们知晓风险/收益的代价。