0

深入Go Module之未说的秘密

 3 years ago
source link: https://colobu.com/2021/07/04/dive-into-go-module-3/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

深入Go Module之未说的秘密

正常情况下,我们的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:

github.com/panicthis/B v1.2
github.com/panicthis/C v1
github.com/panicthis/G/v2 v2

运行go mod tidy它们会被转换成

github.com/panicthis/B v1.2.1
github.com/panicthis/C v1.4.0
github.com/panicthis/G/v2 v2.0.0

go get命令也一样,你也可以直接指定major,忽略minor和patch, 比如

go get github.com/panicthis/[email protected]
go get github.com/panicthis/C@v1
go get github.com/panicthis/G/v2@v2

latest, upgrade 和 patch

有三个单词有特别的语义

  • latest: 选择最高的release版本,如果没有release版本,则选择最高的pre-release版本,如果根本就没有打过tag,则选择最高的伪版本号的版本(默认分支的最后的提交版本)
  • upgrade: 类似latest,但是如果有比release更高的版本(比如pre-release),会选择更高的版本
  • patch: major和minor和当前的版本相同,只把patch升级到最高。当然如果没有当前的版本,则无从比较,则patch退化成latest语义

比如下面的格式:

github.com/panicthis/D latest
github.com/panicthis/E upgrade
github.com/panicthis/F patch

使用go get命令也一样

go get github.com/panicthis/D@latest
go get github.com/panicthis/E@upgrade
go get github.com/panicthis/F@patch //因为没有本地版本,所以此命令在go 1.16下可能出错
go get -u=patch github.com/panicthis/[email protected]

指定特定的commit id

因为有时候proxy有缓存时间或者更新周期,如果你提交了一个新的commit,或者新打了一个tag,通过 latest不一定能拉取到最新的提交,这个时候你可以通过指定commit id的方式拉取。或者你就想测试某个特定的版本。

github.com/panicthis/H 4f7657a
go get github.com/panicthis/H@4f7657a

甚至,你可以使用HEAD,作为你最新的commit id:

github.com/panicthis/H HEAD
go get github.com/panicthis/H@HEAD

特定的分支

你还可以拉取特定的分支

github.com/panicthis/J master
github.com/panicthis/K feat-123
go get github.com/panicthis/J@master
go get github.com/panicthis/K@feat-123

更有甚者,你可以使用>>=<<=比较符,选取某个符合条件的最大的版本。

github.com/stretchr/testify >v1.7.0
github.com/panicthis/F >=v1.1.0
github.com/panicthis/F <v1.1.0
github.com/panicthis/F <=v1.1.0

运行go mod tidy它会转换成canonical version。

或者(注意命令行中需要使用转义符):

go get github.com/stretchr/testify@\>v1.7.0
go get -u=patch github.com/panicthis/F@\>=v1.1.0
go get -u=patch github.com/panicthis/F@\<v1.1.0
go get -u=patch github.com/panicthis/F@\<=v1.1.0

虽然我们可以在go.mod中使用non-canonical version,但是在提交和发布的时候,我们需要使用go mod tidy把它们转换成canonical version,让依赖库的版本对应一个确定的版本,否则masterHEAD在不同的人使用的时候可能会对应不同的版本。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK