原文地址:Chronologic Versioning 2019.05.19
作者:Paul Anthony Webb

摘要

给定版本号格式 年.月.日.变更标识符,增加规则如下:

  1. 当年份改变时,递增年
  2. 当月份改变时,递增月
  3. 当日改变时,递增日
  4. 当项目每次提交变更时,都要改变变更标识符

介绍

在软件管理领域,存在一个被称为“依赖地狱”的可怕现象。当系统规模越来越大,集成到软件中的依赖包越来越多时,某一天就会发现自己深处绝望之中。

在具有较多依赖的系统中,发布新的软件包版本可能很快就成为噩梦了。如果依赖关系过于严格,就存在版本锁定的危险(无法在不升级发布每个依赖包版本的情况下升级软件包)。如果依赖关系过于宽松,就将不可避免的受困于混乱的版本(假设与更多未来版本的兼容性超出了合理范围)。依赖地狱就是,当我们受困于版本锁定或版本混来带来的一系列问题而无法轻松安全的推动项目前进。

作为该问题的解决方案,我提出了一组简单的基于时间的规则和要求,来规定版本号是如何分配以及递增的。我们将通过版本号的特定增量,来表达项目的变动。思考一下这样一个版本格式——A.B.C.D(年.月.日.变更标志符)。如果在当天没有新的二次变更,可以不添加D部分内容。例如:

有一天我们开启了一个新的项目,版本号为2006.04.01。当天晚些时候,我们在该项目提交了一次变更,版本号则为2006.04.01.1。第二天,我们在该项目的首次提交版本将会是2006.04.02

我称此方案为“时间版本控制”。在该方案下,版本号以及递增规则相比其它版本控制方案更容易理解,不再需要通过任意版本的更新或回滚来纠正已发布版本的错误。

时间版本控制规范

文档中出现的关键词"MAY"、"MUST"、"MUST NOT"、"OPTIONAL"、"RECOMMENDED"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"都是按照RFC 2119中的描述进行解释。

  1. 版本号必须采取A.B.C.D的格式,其中各位均为非负整数。A和D不得(MUST NOT)包含前置零。当B和C为一位数时,必须(MUST)包含前置零。A代表年份版本,B代表月份版本,C代表每日版本,D代表当天变更版本数。每一位版本号必须(MUST)按照数字递增的规则增加。例如:2006.04.01 -> 2006.04.02 -> 2006.04.03。
  2. 在上述版本号示例中,若D为零,则为可选状态(OPTIONAL)。例如:2006.04.01 等价于 2006.04.01.0
  3. 如果引入了向后不兼容的变更,则必须(MUST)添加连字符以及保留标签"break"。例如:2006.04.03.12 -> 2006.04.03.12-break。
  4. 一旦发布了版本化的软件包,版本号将不得(MUST NOT)进行修改。任何修改都必须(MUST)作为新版本发布。

为什么要使用时间版本控制

使用其它版本控制方案时,如何统一严谨得去遵循规则是一件较难的事情。当应用程序一年仅发布几次或更少的情况时,这时采用语义化版本控制或许更为合适。但我们现在处于持续交付/集成的时代,对于高速迭代的web应用或其它软件包来说,一个 v3.5.27 的版本号将很快被迭代的版本所淹没。我们的用户基本上不会对版本号感兴趣,也不会去深究在这个版本号所添加的内容。也许有些人会去破译这样一个版本号 10.14.5 (18F127a) 的含义 ,但相比较来说 2019.04.29.5 这样一个版本号更加容易阅读理解。

尽管开发人员更加偏爱结构化和顺序化,也从中受益匪浅。而通过使用时间版本控制方案,几乎可以不假思索的就能遵循其版本规则。尽管其它版本控制方案肯定仍具有其自身的用途,但时代已变,这些方案的作用也就相应的有所变化了。

使用时间版本控制方案会有一个令人愉快的附加作用,我们能够一目了然地看到项目中的哪些依赖(同样使用了时间版本控制方案)已经有一段时间没更新过了。

时间版本控制方案为我们提供了一种稳健的思考方式去管理项目中的依赖,从而节省了时间和免去了不必要的麻烦。

如果所有的这些听起来都十分可取,那么开始使用时间版本控制方案所需要做得就是像现在声明的这样,并遵守规则。可以将本文的链接附在项目的README中,以便其他人能够知道这些规则并从中受益。

常见问题

这个版本控制方案是不是在鼓励高速的发展迭代?

当然是啦,时间版本控制方案致力于软件高速的发展。

对个人项目来说,这看起来非常整洁有序,但是在团队协同中该如果有效使用呢?

标记功能版本是许多团队通用的工作流程。以下是一个时间版本控制方案在团队协作中的示例。想象以下,现在我们的团队正在开发某个功能,并将任务拆分成了UI和执行两条开发分支。

2019.05.08.14 (base release)
├─ 2019.05.08.14-super-ui-enhance (UI fork)
│  └─ 2019.05.08.14-super-ui-enhance.13 (UI fork, later in the day)
└─ 2019.05.08.14-super-ui-please-work (implementation fork)
   └─ 2019.05.08.14-super-ui-please-work.57 (implementation fork, later in the day)

正如我们看到的,super-ui-enhance 和 super-ui-please-work 两条分支是从 2019.05.08.14 这个版本中创建而成。

第二天的某些时候,这两条分支版本看起来就会像这样:

  • 2019.05.09-super-ui-enhance
  • 2019.05.09-super-ui-please-work.9

当两条分支合并之后,就可以放心得省略-FEATURE_NAME.CHANGESET_IDENTIFIER部分了。

我应该如何处理过时的功能?

废弃现有功能是软件发展中的必然途径,当需要废弃现有功能时,应该做两件事情:

(1)更新文档告知使用者功能的变更

(2)发行一个新版本,并以特定方式提示用户

v1.2.3是时间版本控制方案吗?

不是,但在版本号前加上v(version的缩写)是一种常见的方式,以表明这是版本号。例如:git tag v2006.04.03.13 -m "Release version 2006.04.03.13",其中 v2006.04.03.13是标签名,而时间版本是 2006.04.03.13。

文章来源于腾讯云开发者社区,点击查看原文