前言
事情是这样子的, 我们现在 golang 版本是 1.13
, 并且采用了 Go Module 作为第三方包管理工具: 初试 Go Module, 正常情况下我们有一个内部的公共库,比如叫 igong, 存放一些公共抽象出来的方法, 供各个程序去调用。
有一次,我正常给 igong 包打 tag 之后,tag 版本号为 v1.8.7
, 这时候我们的具体程序去更新这个 igong 包的时候, 却报错了:
1 | F:\example_code\gopush-air>go get -u gitlab.example.com/example-utils/iGong |
发现在更新这个 igong 包版本的时候, 获取某一个依赖的时候, 一直报错。 好像一直去下载一个不存在的资源 https://github.com/qiniu/bytes
, 这个包在 github 上已经找不到了。
后面去 igong 包看了一下,发现 igong 项目的 go.mod 确实是有间接引用这个包,不过之前是因为这个包已经不在 github 上面了, 所以就用 replace 将下载地址引入到我们自己的内部私有库,让其可以下载并应用:1
replace github.com/qiniu/bytes => gitlab.example.com/qiniu/bytes v0.0.0-20191012100200-92558a444c07
但是问题就出现在这里, 如果作为第三方被引用的包 igong 里面还有 replace 语法去对一些已失效的包的下载地址进行替换的话, 那么在这个第三方 igong 被其他程序导入的时候, 这时候 go module 进行下载的时候, 好像不会再去 参照 igong 的 go.mod 的 replace 语法。 而是只按照 igong go.mod 的依赖去进行下载, 所以就会导致下载失败的情况。 我不知道 golang 更高一点的版本有没有修复, 但是在我使用的 1.13
版本,确实存在这个 bug, 所以解决方法就是将 igong 的 go.mod 的这个 replace 语句,也一样拷贝一份到我们的当前程序,这样子就可以了。 当然最好的解决方式,就是内部公共包最好不要使用 replace 语句
举个例子:
1 | 当前程序 A , 引用 内部公共库 B, 内部公共库的 go.mod 使用了 replace 语句去替换一些下载链接失效的依赖包 C ->replace-> D, 最后其实下载的是 D 包 |
后续
后续的这个公共包 B,终于将七牛的版本升级到 7.0
版本了,并打了 tag v1.8.8
,所以 B 的 go.mod 就没有 replace 子句了。接下来就是在 A 项目中升级 B 的版本,并且将 A 的 replace 子句去掉, 但是我在移除 A 项目的 replace 子句的时候, 遇到了问题,因为我如果只是将 B 的版本升级到最新版是没问题的, 但是 replace 子句还是在,并不会移除。 如果直接在 go.mod 文件中移除, 那么执行 go mod verify
会报错。
所以我后面的做法是:
- 在 A 的 go.mod 中,先将 B 的公共包依赖移除掉:
1
go mod edit -droprequire=gitlab.example.com/example-utils/iGong
这时候之前依赖他的两个 replace 子句就没有用了。
- 然后在 A 的 go.mod 将这两个 replace 子句删除掉
同时重新装上 B 的最新版本:
1
go get gitlab.example.com/example-utils/iGong
执行
go mod tidy
移除掉不需要的依赖 (其实就是 replace 子句的那两个依赖)- 执行
go mod verify
进行包校验
这样子就可以成功的将 B 版本升级上来的同时将 replace 子句移除掉。