简述
Go 在做依赖管理时会创建两个文件,go.mod 和 go.sum
go.mod 提供了依赖版本的全部信息,类似php的composer.json
go.sum 具体的版本,类似php的composer.lock
go.sum
格式
<module> <version> <hash>
<module> <version>/go.mod <hash>
module是依赖的路径,version是依赖的版本号。hash是以h1:开头的字符串,表示生成checksum的算法是第一版的hash算法(sha256)
注:有些项目实际上并没有 go.mod 这个文件,所以 Go 文档里提到这个 /go.mod 的 checksum,用了 “possibly synthesized” (也许是合成的)的说法。
估计对于没有 go.mod 的项目,Go 会尝试生成一个可能的 go.mod,并取它的 checksum
如果只有对于 go.mod 的 checksum,那么可能是因为对应的依赖没有单独下载。比如用 vendor 管理起来的依赖,便只有 go.mod 的 checksum
version规则
- 项目是否打tag?
如果项目没有打 tag,会生成一个版本号,格式如下:
v0.0.0-commit日期-commitID
引用一个项目的特定分支,比如 develop branch,也会生成类似的版本号:
v当前版本+1-commit日期-commitID
- 项目有没有用 go module?
如果项目有用到 go module,那么就是正常地用 tag 来作为版本号
如果项目打了 tag,但是没有用到 go module,为了跟用了 go module 的项目相区别,需要加个 +incompatible 的标志
- 项目用的 go module 版本是不是 v2+?
通过让依赖路径带版本号后缀来区分同一个项目里不同版本的依赖
对于使用了 v2+ go module 的项目,项目路径会有个版本号的后缀
实现的目标
- 提供分布式环境下的包管理依赖内容校验
Go 采用分布式的方式来管理包。这意味着缺乏一个可供信赖的中心来校验每个包的一致性
在主流的包管理机制中,通常存在一个中央仓库来保证每个发布的版本的内容不会被篡改。比如在 pypi 里面,即使发布过的版本存在严重的bug,发布者也不能重新发布一个同样版本,只能发布一个新版本
并没有一个中央仓库。发布者在 GitHub 上给自己的项目打上 0.1 的 tag 之后,依旧可以删掉这个 tag ,提交不同的内容后再重新打个 0.1 的 tag。
哪怕发布者都是老实人,发布平台也可能作恶。所以只能在每个项目里存储自己依赖到的所有组件的 checksum,才能保证每个依赖不会被篡改
- 作为 transparent log 来加强安全性
它不仅仅记录了当前依赖的checksum,还保留了历史上每次依赖的 checksum
transparent log 旨在维护一个 Append Only 的日志记录,提高篡改者的作案成本,同时方便审查哪些记录是篡改进来的
go.sum 之所以要用 transparent log 的形式记录历史上的每个checksum,是为了便于 sum db 的工作
麻烦
- 容易产生合并冲突
由于许多项目都没有通过打tag的方式来管理发布,每个commit都相当于新发布一个版本,这导致拉取它们的代码时会偶尔往 go.sum 文件里插入一条新记录。go.sum会记录间接依赖的特性,更是让这种情况雪上加霜
- 对于胡乱操作的第三方库,缺乏约束能力
如果一个库乱改已经发布的版本,会让依赖这个库的项目构建失败。对此库的使用者除了咒骂几句,在 issue 或别的地方痛斥作者,然后更新go.sum文件,似乎也没别的解决办法。犯错的本来是库的作者,麻烦的却是库的用户
- 实际情况下,手动编辑go.sum不可避免
有些项目只在go.sum里保留依赖的最新版本的checksum。
如果 go.sum 不是完全由工具管理的,又怎么能保证它一定是 Append Only 呢?如果 go.sum 不是 Append Only 的,又怎么能把它当作 transparent log 使用呢?
演进
GOPATH
GOPATH 模式下,go get 命令使用时,没有版本选择机制,拉下来的依赖代码都会默认当前最新版本,而且如果当项目 A 和项目 B 分别依赖项目 C 的两个不兼容版本时, GOPATH 路径下只有一个版本的 C 将无法同时满足 A 和 B 的依赖需求
- vendor机制
Go1.5提出实验性质的,每个项目下都可以有一个vendor目录存放项目所需版本依赖的拷贝
衍生出govendor godep 等版本管理工具
Go modules
vgo 发展而来,Go1.11 发布该功能
- 相关的环境变量
GO111MODULE="auto"
GOPROXY="https://goproxy.io,direct"
GONOPROXY=""
GOSUMDB="sum.golang.org"
GONOSUMDB=""
GOPRIVATE=""
相关命令操作
go help mod
下载包
获取帮助go help get