版本控制#

本讨论涵盖 Python 软件包版本控制的所有方面。

有效版本号#

不同的 Python 项目可能会根据该特定项目的需要使用不同的版本控制方案,但为了与 pip 等工具兼容,所有项目都必须遵守版本标识符的灵活格式,其权威参考是 版本说明符规范。以下是一些版本号示例 [1]

  • 简单版本(最终版本):1.2.0

  • 开发版本:1.2.0.dev1

  • Alpha 版本:1.2.0a1

  • Beta 版本:1.2.0b1

  • 候选版本:1.2.0rc1

  • 后发布版本:1.2.0.post1

  • Alpha 版本的后发布版本(可能,但不建议):1.2.0a1.post1

  • 只有两个组件的简单版本:23.12

  • 只有一个组件的简单版本:42

  • 带有纪元的版本:1!1.0

项目可以使用预发布周期来支持用户在最终发布之前进行测试。按顺序,步骤如下:Alpha 版本、Beta 版本、候选版本、最终版本。默认情况下,Pip 和其他现代 Python 软件包安装程序在决定安装哪个版本的依赖项时会忽略预发布版本,除非明确要求(例如,使用 pip install pkg==1.1a3pip install --pre pkg)。

开发版本的目的是支持在开发周期早期发布的版本,例如,夜间构建或从 Linux 发行版中的最新源构建。

后发布版本用于解决最终版本中的小错误,这些错误不会影响已分发的软件,例如更正发行说明中的错误。它们不应用于错误修复;这些应该通过新的最终版本来完成(例如,在使用语义版本控制时增加第三个组件)。

最后,纪元是一种很少使用的功能,用于在更改版本控制方案时修复排序顺序。例如,如果项目正在使用日历版本控制,版本为 23.12,并切换到语义版本控制,版本为 1.0,则 1.0 和 23.12 之间的比较将出错。为了纠正这一点,新版本号应该有一个明确的纪元,如“1!1.0”,以便被视为比旧版本号更新。

语义版本控制与日历版本控制#

版本控制方案是一种形式化的方式,用于解释版本号的各个部分,并决定新发布的包的下一个版本号应该是什么。语义版本控制和日历版本控制是两种通常用于 Python 包的版本控制方案。

警告

选择哪个版本号的决定取决于项目的维护者。这实际上意味着版本升级反映了维护者的观点。该观点可能与最终用户对所述形式化版本控制方案对他们的承诺的看法不同。

有已知例外情况可用于选择下一个版本号。维护者可能有意选择打破最后一个版本部分只包含向后兼容更改的假设。其中一个案例是需要解决安全漏洞。安全版本通常采用补丁版本,但不可避免地包含重大更改。

语义版本控制#

语义版本控制(或 SemVer)的理念是使用 3 部分版本号,major.minor.patch,其中项目作者递增

  • major 当他们进行不兼容的 API 更改时,

  • minor 当他们以向后兼容的方式添加功能时,以及

  • patch,当他们进行向后兼容的错误修复时。

大多数 Python 项目使用类似于语义版本控制的方案。然而,大多数项目,尤其是较大的项目,并没有严格遵守语义版本控制,因为许多更改在技术上是重大更改,但只影响一小部分用户。此类项目倾向于在不兼容性较高时或为了表示项目发生了转变而不是为了任何微小的不兼容性而递增主要版本号 [2]。相反,有时会使用主要版本号的升级来表示重大但向后兼容的新功能。

对于确实使用严格语义版本控制的项目,此方法允许用户使用 兼容版本规范,使用 ~= 运算符。例如,name ~= X.Y 大致等同于 name >= X.Y, == X.*,即它至少需要版本 X.Y,并允许任何更高版本的 Y 只要 X 相同。同样,name ~= X.Y.Z 大致等同于 name >= X.Y.Z, == X.Y.*,即它至少需要 X.Y.Z 并允许更高版本的 X 和 Y 但 Z 更高。

采用语义版本控制的 Python 项目应遵守 语义版本控制 2.0.0 规范的第 1-8 条。

流行的 Sphinx 文档生成器是一个使用严格语义版本控制的示例项目(Sphinx 版本控制策略)。著名的 NumPy 科学计算包明确使用“松散”语义版本控制,其中递增次要版本的版本可能包含向后不兼容的 API 更改(NumPy 版本控制策略)。

日历版本控制#

语义版本控制并不适合所有项目,例如那些具有基于时间的定期发布节奏和在删除功能之前提供多个版本警告的弃用流程的项目。

基于日期的版本控制或 日历版本控制(CalVer)的一个主要优势在于,仅给定版本号就可以轻松地判断特定版本的底层功能集有多旧。

日历版本号通常采用年.月格式(例如,2023 年 12 月为 23.12)。

Pip,标准 Python 包安装程序,使用日历版本控制。

其他方案#

序列版本控制是指最简单的版本控制方案,它由一个每次发布都递增的单一数字组成。虽然序列版本控制对于开发人员来说非常容易管理,但对于最终用户来说却是最难跟踪的,因为序列版本号几乎不传达有关 API 向后兼容性的信息。

上述方案的组合是可能的。例如,一个项目可以将基于日期的版本控制与序列版本控制相结合,创建一个年.序列编号方案,该方案可以轻松地传达版本的近似年龄,但不会在一年内承诺特定的发布节奏。

本地版本标识符#

公共版本标识符旨在支持通过 PyPI 进行分发。Python 打包工具还支持 本地版本标识符 的概念,可用于标识不打算发布的本地开发版本,或由再发行商维护的已发布版本的修改变体。

本地版本标识符采用公共版本标识符的形式,后跟“+”和本地版本标签。例如,应用了特定于 Fedora 的补丁的包的版本可以是“1.2.1+fedora.4”。另一个示例是通过 setuptools-scm 计算的版本,setuptools-scm 是一个从 Git 数据读取版本的 setuptools 插件。在自上次发布以来已进行了一些提交的 Git 存储库中,setuptools-scm 会生成类似“0.5.dev1+gd00980f”的版本,或者如果存储库有未跟踪的更改,则会生成类似“0.5.dev1+gd00980f.d20231217”的版本。