Go Module 实践中的问题(持续更新)


项目逐渐都切到了 go mod,用的时候遇到了各种奇奇怪怪的坑,记录一下。

流程实践

语义化版本

Go mod 在设计时没有支持诸如 >2.0, ~3.4, ^4.0 这样场景的语法。而是以语义化版本的约定来处理:

x.y.z^x.y + <=y.z

实际中,对于内部频繁升级的 common 包,每次改动都需要 y+=1 才能保证兼容性。为此我专门搞了个小玩意来升级 y,可以通过 hook 在 push 前先 gt ft

有个比较恶心的问题,common 包的版本号长期维持在 1.y.0 且 y 很大。暂时没用解决的办法,后面再看看 x 能有什么新玩法。

不同分支依赖冲突

如图,一个常见的场景,多人开发项目时,有可能在开发过程中使用了不同的依赖包,在合并代码的时候也会冲突。

以前的办法是有个专门的 vendor 分支,把有关依赖的变动串行化。

但是用了 gomod 后,如果你只在 vendor 分支 里加了依赖没有用,go mod tidy 时又会把依赖给去掉。

好在大部分时候都是需要更新而不是新增依赖,这个思路依然可用。我们给项目里专门准备了一个脚本来升级依赖,这个脚本做的事情也比较简单,切换到 vendor 分支,更新,提交。再合回 feature 分支。

异常问题处理

go replace 替换大小写时不支持同时依赖大小写

P->A P->xx->a

天真以为把 A replace a 就好了。还是会报同时用了大小写的错。

只有当所有依赖都依赖 A,但是 github 已经改成 a 时,才能 replace。

问题最初是由于 github.com/sirupsen/logrus 更换大小写引起,如果项目全用 Sirupsen 是可以 replace 的,后来有了混用就不行了。终极解决办法是干掉 logrus 。。

凡是随意修改包路径、函数签名的 Go Libs,基本上都被我列入黑名单了。

build xx: ambiguous import: xx in multiple modules:

通常是在没有使用语义化版本时,对一个包有不同版本的依赖导致。例如:

build xxx.com/com/projA: cannot load xxx.com/com/projB/model: ambiguous import: found xxx.com/com/projB/model in multiple modules:
	xxx.com/com/projB v0.0.0-20181119101949-92ae1f75b49a (.../pkg/mod/xxx.com/com/projB@v0.0.0-20181119101949-92ae1f75b49a/model)
	xxx.com/com/projB/model v0.0.0-20190311082816-bfb94e79a84f (.../pkg/mod/xxx.com/com/projB/model@v0.0.0-20190311082816-bfb94e79a84f)

可以通过下面方式来找

fd go.mod | xargs grep -r projB
vendor/xxx.com/com/base/go.mod:	xxx.com/com/projB/registry v0.0.0-20190312132550-a101ae8810b6 // indirect
vendor/xxx.com/com/artemis/go.mod:	xxx.com/com/projB/app/goprojB v0.0.0-20190312132550-a101ae8810b6
vendor/xxx.com/com/projB/registry/go.mod:module xxx.com/com/projB/registry

go replace 不能替换依赖包的依赖

我的项目P -> A&B,且 B->A

如果把 A replace 成 A‘,只能修改 P->A 的依赖, B->A 是改不了的。

所以 replace 不能解决梯子的问题,要用 goproxy

go get: error loading module requirements

go clean -modcache

清理 modcache 几乎是各种问题的终极大杀器,但是成本也很高,需要你下次重拉所有 mod。如果公司内有 proxy 做 cache 的话会好一些。

Avatar
huiren
Code Artisan

问渠那得清如许,为有源头活水来

下一页
上一页
comments powered by Disqus