7

如何调试 Go mod 的各种异常

 3 years ago
source link: https://ms2008.github.io/2020/10/31/go-mod/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Go mod 自从诞生之日就带来了太多太多的争议,当然不能否认它的设计初衷是好的。然而在调试其各种异常时,却浪费了太多开发者的时间。可以毫不客气的说,从来没有一种语言的版本管理,能让人如此崩溃

本文记录了一些我的踩坑经验,希望能给还在挣扎中的 Gopher 一些帮助。

go get

先来看看最近我遇到的一个问题:

$ go mod tidy
go: foo.bar.com/foo/[email protected]: git remote add origin -- https://foo.bar.com/foo/bar.git in /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2: exit status 128:
        fatal: remote origin already exists.

光从字面上来看,像是一个 git 的问题。一顿 go mod whygo mod graph 操作后,也没有得到什么有价值的信息。

以我的个人摸索经验来看,whygraph 的输出就是一坨垃圾,只会给开发者带来更多的心智负担。

实际上,调试 go mod 问题最好的工具是 go get ,这样可以只会输出异常模块的依赖树,去掉那些烦人的干扰信息。如果再加上 -x 选项后,更是屡试不爽。继续拿我遇到的这个问题开刀:

$ go get -x foo.bar.com/foo/bar
# get https://foo.bar.com/foo/bar?go-get=1
# get https://foo.bar.com/foo/bar?go-get=1: 200 OK (0.508s)
mkdir -p /root/goforge/pkg/mod/cache/vcs # git3 https://foo.bar.com/foo/bar.git
# lock /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2.lockmkdir -p /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2 # git3 https://foo.bar.com/foo/bar.git
cd /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2; git init --bare
0.011s # cd /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2; git init --bare
cd /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2; git remote add origin -- https://foo.bar.com/foo/bar.git
0.006s # cd /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2; git remote add origin -- https://foo.bar.com/foo/bar.git
go: foo.bar.com/foo/[email protected]: git remote add origin -- https://foo.bar.com/foo/bar.git in /root/goforge/pkg/mod/cache/vcs/e8ae9003fdd7f44246f94c535282e58436b3568a39734a76af8fac7b716a59b2: exit status 128:
        fatal: remote origin already exists.

瞧,go get -x 会帮你把每个步骤的操作都打出来。显然这个问题确实由 git 引起。大概是 go get 拉取模块时,会先创建一个裸仓库,然后 add origin 。问题就发生在 add origin 这步,git 认为已经有一个 origin 存在了。这是为啥呢?不妨去手动复现下:

$ mkdir git_test
$ cd git_test
$ git init
$ git remote add origin -- https://foo.bar.com/foo/bar.git
fatal: remote origin already exists.

继续看看,现在这个仓库的 origin 是啥:

$ git remote -v
origin

看到这里,突然想起我的 git 配置了 origin 默认指向 HEAD

$ git config -l | grep origin
branch.master.remote=origin
remote.origin.push=HEAD

git 2.20 以上已经在一个空的 origin 上继续 add 了

删除了这个选项后:git config --global --unset remote.origin.push, 终于可以拉取成功了。

replace

试想这么一种场景,假设有个项目 foo 依赖 a 的 v1.0.0 版本,而 foo 依赖的 b 依赖了 a 的 v2.0.0 版本。那么这个时候 foo 的 mod 其实最终会依赖 a 的 v2.0.0 版本。如果你需要 foo 强行依赖 v1.0.0 版本,这个时候就派上了 replace 的上场。直接修改 go.mod 文件,添加:replace a => a v1.0.0 即可。

但是实际情况,往往会更复杂。比如 b 需要 a v2.0.0 的一些新特性的话,简单的 replace 往往不能解决这个问题。如何解决呢?自己去处理。比如,Kuma 自己维护了一个 vendored 文件夹 replace 到本地来处理这种问题;Kubernetes 也有个自己的 staging

mod cache

需要注意的是 go 1.12 版本之前,mod cache 并不是并发安全的,同一个环境并发构建可能会产生竞态。而最新的 go 1.15 还提供了环境变量 GOMODCACHE 来指定 mod cache 的位置,CI 工具可以利用这项加快构建速度。



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK