如何解决语义版本控制 2 零案例
查看SemVer 2.0 guidelines后,我有以下问题:
根据他们的 BNF 语法,提供的两个例子都被认为是有效的,但这有意义吗?
解决方法
是的,0.0.0
是有效的。
是的,-alpha.0
是有效的。
据我所知,包括 BNF 在内的整个规范都“有意义”,但您必须在这个领域呆一段时间才能真正理解原因。出于某种原因,规范并不冗长。它只说它需要说的,以便工具制造商可以编写合规的代码,工具用户可以拥有尽可能多的自由。事实上,在编写规范之前,已经有一些工具在使用,它们使用了类似的语法和语义。
所以,0.0.0
是有效的,因为他们没有强有力的论据反对它。这就像围绕编程语言应该使用基于零还是基于一的数组索引的无休止的争论。无论哪种方式,都有理由去做和不做。规格不应该比它们绝对需要的更加固执己见,这是最好将其留给最终用户的情况之一。工具必须接受 0.0.0
,但不必生成它。它实际上需要规范中的额外单词,以及工具中的额外代码来将 0.0.0
解释为无效输入。没有客观的理由进行演练。
至于 prerelease 标签中的零字段,没问题,但 -alpha.00
不是。规范禁止“前导零”,因为它们会搞砸排序。售前标签由连字符“-”和一系列点分隔的数字或字母数字字段组成。您示例中的“.0”是规范定义的有效数字字段。
考虑项目的初始状态。也许您的 DevOps 团队有一个项目模板设置,其中有所有构建配置可供您克隆,然后开始处理您的项目。此时有两种选择。要么没有与初始项目状态相关联的版本,要么它被初始化为某个起始值。在后一种情况下,从哪个版本号开始? 0.0.0
似乎是个好主意。也许构建自动化读取该版本,读取提交消息,并选择合适的下一个版本。如果必须处理缺少版本的情况,该工具会更加复杂。当一个有效的静态值可以存储在某个地方时,为什么要支付携带该代码的运行时损失?
SemVer spec 实现了三个主要目标中的两个:
- 它定义了版本三元组 + 标签的语法和语义。
- 它定义了版本字符串的排序方式。
- 尝试缓解依赖地狱(仅部分成功)。
#1 的某些元素是为了支持 #2。规范的“语义”部分是为了减轻依赖地狱带来的一些痛苦,但语法和其他规则与排序一样,与其他任何规则一样。让我们从 #2 开始:
#2 普通版本号必须采用 X.Y.Z 形式,其中 X、Y 和 Z 是非负整数,并且不得包含前导零。 X 是主要版本,Y 是次要版本,Z 是补丁版本。每个元素必须在数字上增加。例如:1.9.0 -> 1.10.0 -> 1.11.0。
第一句:“普通版本号必须采用 X.Y.Z 形式,其中 X、Y 和 Z 是非负整数,并且不得包含前导零。”
“非负整数”部分明确允许在任何或所有字段中使用零。请参阅 0 Wikipedia,特别是“作为数字,0 用作位值系统中的占位符”。 SemVer 属于“地方价值系统”。
“不得包含前导零”位用于支持排序。虽然规范稍后说数字字段是“数字比较”,但数字数字的 ASCII 码点是 48..57 (0..9),因此不必将每个字段转换为整数,以便排序它。排序时,我们一次比较每个码点一个,直到其中一个不同,或者我们发现它们的长度不同。前缀相等,两个字符串中较长的字符串大于较短的字符串。如果我们允许前导零,那么我们将需要先将字段转换为整数(因为“00”>“0”没有意义),这将需要两倍多的工作。
#9 预发布版本可以通过在补丁版本之后立即附加连字符和一系列点分隔标识符来表示。标识符必须仅包含 ASCII 字母数字和连字符 [0-9A-Za-z-]。标识符不得为空。数字标识符不得包含前导零。预发布版本的优先级低于相关的普通版本。预发布版本表示该版本不稳定并且可能不满足其关联的正常版本所表示的预期兼容性要求。示例:1.0.0-alpha,1.0.0-alpha.1,1.0.0-0.3.7,1.0.0-x.7.z.92,1.0.0-x-y-z.–.
第二句:“标识符必须仅包含 ASCII 字母数字和连字符 [0-9A-Za-z-]”将预发布标签字段限制为 ASCII 代码点范围 48..57,65 ..90 和 97..122。此规则与 #11 相结合,有助于使排序变得几乎无足轻重。
#11 优先级是指在订购时如何相互比较版本。
- 必须按顺序将版本分为主要、次要、补丁和预发布标识符来计算优先级(构建元数据不计入优先级)。
这条规则的原因很简单。如果您对整个字符串应用标准 ASCII 排序规则而不考虑字段,则会出现许多异常,例如 1.999.0
排序高于 2.0.0
。
- 从左到右比较每个标识符时的第一个差异确定优先级,如下所示:主要版本、次要版本和补丁版本始终按数字进行比较。
示例:1.0.0
现在这里是 #9 中的“标识符不得为空”位发挥作用的地方,这也是为什么在某些字段中不禁止零的原因之一。如果你得到字符串“1.1”。甚至“1.1”,您可能会推断出次要字段为空,但如果您可以依靠存在的值,并且不必实现字段为 NULL (C/C++) 或某些的特殊情况,则会更方便其他“未初始化”状态。因此规范要求在该字段中使用占位符“0”,而对于您可能在其中实现解析和比较代码的某些语言,它更易于处理。
请注意,某些工具始终支持简写形式“1”和“1.1”,但这是实现者的选择并且不合规。该规范需要完整的三元组进行互操作,并减少人类查看字符串的认知负担。固定的三重格式不太可能被人类误解。完整的三元组还提供了一点点消除 SemVer 字符串与其他版本控制方案的歧义(可能有点自以为是的规范)。
- 当主要版本、次要版本和补丁版本相同时,预发布版本的优先级低于普通版本:
示例:1.0.0-alpha
实际上有两种预发布版本,但作者显然没有发现有必要指出 0.1.0-experimental
- 具有相同主要版本、次要版本和补丁版本的两个预发布版本的优先级必须通过从左到右比较每个点分隔的标识符来确定,直到找到如下差异:
仅由数字组成的标识符在数字上进行比较。
带有字母或连字符的标识符按 ASCII 排序顺序在词法上进行比较。
数字标识符的优先级总是低于非数字标识符。
如果所有前面的标识符都相等,则较大的预发布字段集比较小的集具有更高的优先级。
示例:1.0.0-alpha
事情变得有趣了。给定 -alpha.1 和 alpha.a,您可能认为您可以将最后一个字段视为字母数字(其中一个是对的?),因此我们可以将该字段解释为字母数字并按 ASCII 代码点排序,在在这种情况下 -alpha.1 数字标识符总是比非数字标识符具有更低的优先级”,但这也给了我们 -alpha.1
它没有在任何地方指定,但我怀疑以下标签历史似乎比规范的其他定义方式更自然:
-0
因为从最早的计算时代开始,这就是一个标准的归类。
现在大多数实现尝试将字段转换为整数或其他数字类型,并在成功时将字段视为数字或在失败时将字段视为字母数字。如果两个字段都是数字,它们最终会直接比较值,这似乎比比较单个代码点要快,但这忽略了转换开销。除了这些转换所需的非最佳空间和时间之外,它们通常会导致不合规的实现。某些编程语言,至少在某些系统上,无法将“-20210313”转换为整数。
事实上,有一些合法的 SemVer 字段不能被准确地表示为适合任何当前系统的寄存器的任何整数或浮点值。该规范对任何字段的长度没有限制。 FAQ 表达了对这一点的意见,但规范没有。即使遵循 FAQ 的建议,即 256 字节的版本字符串足够长,也很容易设计一个可以填充大部分空间的预发布标签字段。因此,要完全符合规范,我们必须:
- 从左到右扫描要比较的字段,一次一个代码点,
- 注意其中一个是否包含非数字字符,
- 并在我们遇到差异时立即应用上述规则。
当然,由于特定的比较算法适用于 SemVer 字符串中每个可能的字段,因此它也恰好是空间和时间最佳的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。