规划、发布和维护 Go Module注意事项
# 规划、发布和维护 Go Module注意事项
仓库布局:一个仓库管理一个 module
- 如果没有单一仓库(monorepo)的强约束,那么在默认情况下,选择一个仓库管理一个 module 是不会错的,这是管理 Go Module 的最简单的方式,也是最常用的标准方式。这种方式下,module 维护者维护起来会很方便,module 的使用者在引用 module 下面的包时,也可以很容易地确定包的导入路径。
- 如果组织层面要求采用单一仓库(monorepo)模式,也就是所有 Go Module 都必须放在一个 repo 下,那只能使用单 repo 下管理多个 Go Module 的方法。Go Module 的设计者 Russ Cox 曾说过:“在单 repo 多 module 的布局下,添加 module、删除 module,以及对 module 进行版本管理,都需要相当谨慎和深思熟虑,因此,管理一个单 module 的版本库,几乎总是比管理现有版本库中的多个 module 要容易和简单”。
发布 Go Module
如果采用单 repo 单 module 管理方式,那么我们给 repo 打的 tag 就是 module 的版本。如果采用的是单 repo 多 module 的管理方式,那么我们就需要注意在 tag 中加上各个 module 的子目录名,这样才能起到发布某个 module 版本的作用,否则 module 的用户通过 go get xxx@latest 也无法看到新发布的 module 版本。
作废特定版本的 Go Module
修复 broken 版本并重新发布
操作步骤理论上很简单:Module 的作者只需要删除掉远程的 tag,在本地 fix 掉问题,然后重新 tag 并 push 发布到 bitbucket 上的仓库中就可以了。
但实际上:现在大家都是通过 Goproxy 服务来获取 module ,这个版本会被缓存在对应的代理服务器上,即使删除出问题的tag,goproxy 服务器的缓存也不会主动删除,拉取的还是有问题的版本tag。
发布 module 的新 patch 版本
从 Go 1.16 版本开始,Go Module 作者还可以在 go.mod 中使用新增加的retract 指示符,标识出哪些版本是作废的且不推荐使用的。retract 的语法形式如下:
// go.mod retract v1.0.0 // 作废v1.0.0版本 retract [v1.1.0, v1.2.0] // 作废v1.1.0和v1.2.0两个版本
1
2
3
升级 module 的 major 版本号
随着 module 的演化,总有一天 module 会出现不兼容以前版本的 change,这就到了需要升级 module 的 major 版本号的时候了。
Go 团队采用了将“major 版本”作为导入路径的一部分的设计。这种设计支持在同一个项目中,导入同一个 repo 下的不同 major 版本的 module,比如:
import ( "bitbucket.org/bigwhite/m1/pkg1" // 导入major版本号为v0或v1的module下的pkg1 pkg1v2 "bitbucket.org/bigwhite/m1/v2/pkg1" // 导入major版本号为v2的module下的pkg1 )
1
2
3
4
在同一个 repo 下,不同 major 号的 module 就是完全不同的 module,甚至同一 repo 下,不同 major 号的 module 可以相互导入。
对于 module 作者 / 维护者而言,升级 major 版本号,也就意味着高版本的代码要与低版本的代码彻底分开维护,通常 Go 社区会采用为新的 major 版本建立新的 major 分支的方式,来将不同 major 版本的代码分离开,这种方案被称为“major branch”的方案。major branch 方案对于多数 gopher 来说,是一个过渡比较自然的方案,它通过建立 vN 分支并基于 vN 分支打 vN.x.x 的 tag 的方式,做 major 版本的发布。