正常情况下,我们的go.mod依赖库的版本都是符合语义化版本 2.0.0的版本格式,或者伪版本格式。在前面的文章我没有特别提到一点的事,Go使用服务端提交的日期和commit id生成的伪版本号是符合语义化版本号2.0.0的,因为语义化版本号中规定pre-release以连接号-加一连串以逗号分隔的标识符组成,标识符以字母数字和连接号组成,所以你看到-yyyyMMddhhmmss-comitid
包含两个连接号,这是正常的。
go要求依赖库要么不包含go.mod,要么依赖库中的go.mod定义的依赖库版本必须以语义化版本 2.0.0格式(或伪版本号)标志(其实更严格,除了+incompatible
不能加meta字段),因为这样我们你能够明确标识某个依赖库确切的版本,这样的版本号被称之为canonical version。
其实main module还可以定义non-canonical version,通过go get或者go mod tidy更新go.mod的时候,命令会尝试更新go.mod,尝试把non-canonical version转变为canonical version版本。
但是,到底有哪些non-canonical version呢?我还没看到官方文章介绍,本文尝试整理这些non-canonical version。
只定义major或者major.minor
你可以不指定minor.patch或者patch,而是让go命令尝试去寻找最大的minor和patch,所以你可以在go.mod只定义vmajor或者vmajor.minor:
|
|
运行go mod tidy
它们会被转换成
|
|
go get
命令也一样,你也可以直接指定major,忽略minor和patch, 比如
|
|
latest, upgrade 和 patch
有三个单词有特别的语义
- latest: 选择最高的release版本,如果没有release版本,则选择最高的pre-release版本,如果根本就没有打过tag,则选择最高的伪版本号的版本(默认分支的最后的提交版本)
- upgrade: 类似latest,但是如果有比release更高的版本(比如pre-release),会选择更高的版本
- patch: major和minor和当前的版本相同,只把patch升级到最高。当然如果没有当前的版本,则无从比较,则patch退化成latest语义
比如下面的格式:
|
|
使用go get命令也一样
|
|
指定特定的commit id
因为有时候proxy有缓存时间或者更新周期,如果你提交了一个新的commit,或者新打了一个tag,通过 latest
不一定能拉取到最新的提交,这个时候你可以通过指定commit id的方式拉取。或者你就想测试某个特定的版本。
|
|
或者
|
|
甚至,你可以使用HEAD
,作为你最新的commit id:
|
|
或者
|
|
特定的分支
你还可以拉取特定的分支
|
|
或者
|
|
≈
更有甚者,你可以使用>
、>=
、<
、<=
比较符,选取某个符合条件的最大的版本。
比如:
|
|
运行go mod tidy它会转换成canonical version。
或者(注意命令行中需要使用转义符):
|
|
虽然我们可以在go.mod中使用non-canonical version,但是在提交和发布的时候,我们需要使用go mod tidy把它们转换成canonical version,让依赖库的版本对应一个确定的版本,否则master
、HEAD
在不同的人使用的时候可能会对应不同的版本。
none
还有一个特殊的字符可以作为non-canonical version,比如
|
|
它会从go module中移出这个依赖。
tip
有人提议支持go从开发分支上拉取最新的版本。 有几个单次可以候选,但是感觉从 hg/mercurial中借鉴来的tip
很合适。go最新的开发版本也叫做tip
。
这只是一个提议,未必最终支持。 #42545