go module的使用技巧
go mod 确实方便,无视翻墙问题,下载啥都可以。
go mod 一般是使用以下命令:
- go mod init xxx
- go mod tidy
- go mod edit
这里着重说下 go mod edit 的作用。
go mod edit 用来修改 go.mod 文件的包的版本关系。
- 修改包版本
-
自定义本地包。方便测试(本地包需要是 module 方式的)
module test go 1.12 require ( gopkg v0.0.0 ) replace gopkg v0.0.0 => ../gopkg
这样就可以实现 module 方式,调用本地包了。
go mod edit 修改go.mod,然而它有两点缺陷:
- 首先是它的-require必须接受“package@version”这种形式,缺一不可,而且不能识别文档规定的master和latest标志。
- edit只适合用于修改依赖版本,给package改名,屏蔽特定的package这三个功能,不适用于添加依赖。
由于以上两个特点,因此有了新版的go get特性。
- go get会自动下载并安装package,然后更新到go.mod
- 使用go get package[@version]来安装指定版本的package,不指定version时默认行为和go get package@latest一样
- version可以是vx.y.z这种形式或者直接使用commit的checksum,也可以是master或者latest
- 当version是latest时,也就是默认行为,对于有tags的package,会选取最新的tag,对于没有tags的package,则选取最新的commit
- 当version是master时,不管package有没有打tag,都会选择master分支的最新commit
- 可以在version前使用>,>=,<,<=,表示选取的版本不得超过/低于version,在这个范围内的符合latest条件的版本
- go get -u可以更新package到latest版本
- go get -u=patch将只更新小版本,例如从v1.2.4到v1.2.5
- 当想要修改package的版本时,只需要go get package@指定的version即可
注意两个坑:
- 没开go mod方式,直接go get,就是拉取最新的master分支。
- 开启go mod,直接go get,拉取的是有打tag,就下载tag的版本,没打tag,就拉取最新的master分支
背景:公司有两个私有项目放在私有 git 上,这里叫 A 和 B,A 项目有引用 B 的包
- 1、go mod 会自动下载最新 tag 的代码,如果没有会自动引入最新的 master 提交,这样没问题。但是有 tag 的情况下只会引入 tag,没法引用最新的代码(如果 B 有改动必须打 Tag ?)
- 2、上面的问题可以用 replace 的方案解决,但是如果团队开发,大家的 gopath 都不一致,go mod 文件会有多份,如何解决?
解决方案:
- 使用replace的相对路径(./或../形式) ,比如:replace github.com/b => ../b
- 手动go get -u github.com/b@branch(或者是commit),go.mod会自动生成 github.com/b@V0.0.0-data-hash
公司通过 gitlab 搭建了私有库,二方依赖库下载不下来怎么办?
这个几乎是最常见的问题,比较简单的解决方案是 hack 一下 git 配置:
git config --global url."git@gitlab.your-company.com:<your>/<package>.git".insteadOf "https://gitlab.your-company.com/<your>/<package>.git"
这个方案依赖你本地的 ~/.ssh/id_rsa, 这样你就可以正常 go get 了。
Dockerfile 中构建镜像怎么解决私有库的依赖包问题?
方案一
上述方式通过修改 git config ,却依赖你本地的 ~/.ssh/id_rsa,在构建时可以通过 multistage-build 把私钥 add 到 stage 0 里面 build,然后用后面新的 stage 生成镜像,这样构建的镜像就不会包含私钥;
方案二
更为安全的方式是,在每次构建 Docker 镜像之前,先在本地用 go mod vendor 把包缓存下来,在 Dockerfile 构建镜像过程中还是用 GOPATH 和 Vendor 机制来管理依赖。