go mod

1
go mod edit [editing flags] [go.mod]

commands

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# upgrade go version to 1.21.4
go mod edit -go 1.21.4

export GO111MODULE=on

go mod init project0    # 初始化
go mod tidy             # 拉取缺少的模块, 移除不用的模块。
go mod download         # 手动下载依赖包, 根据 go.mod 下载
go mod graph            # 打印模块依赖图
go mod vendor           # 将依赖复制到 vendor 下
go mod verify           # 校验依赖
go mod why              # 打印为什么需要依赖
go list all             # 打印所有的 package
go list -m all          # 打印所有的 module, The -m flag causes list to list modules instead of packages
go list -m -json all    # 依赖详情, json 格式
go mod edit -go=1.15

# 添加新模块
go get <package>[@<version>]

go.mod 如何编辑 在 Go 1.16 中,另一个行为变更是 go build 和 go test 不会自动编辑 go.mod 了,基于以上信息,Go 1.16 中将进行如下处理:

通过在代码中修改 import 语句,来修改 go.mod:

go mod tidy 删除掉无用的模块; 将未导入的模块写入 go.mod:

go mod tidy 也可以; 手动编辑;

https://moelove.info/2020/12/19/Go-1.16-%E4%B8%AD%E5%85%B3%E4%BA%8E-go-get-%E5%92%8C-go-install-%E4%BD%A0%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E5%9C%B0%E6%96%B9/

go mod replace

不过因为某些未知原因,并不是所有的包都能直接用 go get 获取到, 这时我们就需要使用 go modules 的 replace 功能了。 (当然大部分问题挂个梯子就能解决,但是我们也可以有其它选项)

使用 replace 替换 package

replace 顾名思义,就是用新的 package 去替换另一个 package, 他们可以是不同的 package, 也可以是同一个 package 的不同版本。看一下基本的语法:

go mod replace 必须带版本号, 不带版本号的 replace 只能用于 replace 到本地目录

replace 到本地的包

1
2
3
4
5
6
7
# replace 到本地的包
# git.xxx.com/path/to/package 参照 go.mod 已有的 require 项, /path/to/local/package 配置到有go.mod文件的那层目录
go mod edit -replace=git.xxx.com/path/to/package@v1.0.2=/path/to/local/package

# replace到本地目录可以不带版本号
go mod edit -replace=github.com/wiloon/pingd-config=/home/wiloon/projects/pingd-config/
go mod edit -replace=github.com/wiloon/w-tcp-proxy=/root/projects/w-tcp-proxy
1
2
3
4
5
6
7
8
# old 是要被替换的package,new就是用于替换的package。
go mod edit -replace=old[@v]=new[@v]

# replace golang sys
go mod edit -replace=golang.org/x/sys@v0.0.0-20190526052359-791d8a0f4d09=github.com/golang/sys@v0.0.0-20190526052359-791d8a0f4d09

#after that, in the go.mod
replace git.xxx.com/path/to/package v1.0.2 => /path/to/local/package
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
replace golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e => github.com/golang/sys v0.0.0-20180909124046-d0be0721c37e

replace golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 => github.com/golang/net v0.0.0-20190404232315-eb5bcb51f2a3

replace golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0

replace golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5 => github.com/golang/crypto v0.0.0-20190404164418-38d8ce5564a5

replace google.golang.org/appengine v1.6.0 => github.com/golang/appengine v1.6.0

这里有几点要注意:

replace 应该在引入新的依赖后立即执行, 以免 go tools 自动更新 mod 文件时使用了 old package 导致可能的失败

package后面的version不可省略。 (edit所有操作都需要版本tag)

version不能是master或者latest,这两者 go get 可用, 但是 go mod edit 不可识别,会报错。 (不知道是不是bug,虽然文档里表示可以这么用,希望go1.12能做点完善措施)

基于以上原因,我们替换一个package的步骤应该是这样的:

首先 go get new-package (如果你知道package的版本tag,那么这一步其实可以省略,如果想使用最新的版本而不想确认版本号,则需要这一步)

然后查看go.mod,手动复制new-package的版本号 (如果你知道版本号,则跳过,这一步十分得不人性化,也许以后会改进)

接着 go mod tidy 或者 go build 或者使用其他的 go tools, 他们会去获取 new-package 然后替换掉 old-package

最后,在你的代码里直接使用old-package的名字,golang会自动识别出replace,然后实际你的程序将会使用new-package,替换成功

下面我们仍然用chromedp的example做一个示例。

示例

chromedp使用了golang.org/x/image,这个package一般直连是获取不了的,但是它有一个github.com/golang/image的镜像,所以我们要用replace来用镜像替换它。

我们先来看看如果不replace的情况下的依赖情况:

没错,我们使用了原来的包,当然如果你无法获取到它的话是不会被记录进来的。

下面我们go get它的镜像:

master表示获取最新的commit

go get github.com/golang/image@master

然后我们查看版本号:

cat go.mod

有了版本号,我们就能replace了:

go mod edit -replace=golang.org/x/image@v0.0.0-20180708004352-c73c2afc3b81=github.com/golang/image@v0.0.0-20180708004352-c73c2afc3b81

现在我们查看一下go.mod:

replace信息已经更新了,现在我们只要go mod tidy或者go build,我们的代码就可以使用new-package了。

更新后的go.sum,依赖已经替换成了镜像:

目前来看,replace做的远不如go get那样方便人性化,不过毕竟还只是测试阶段的功能,期待一下它在go1.12的表现吧。

如果有错误和疑问,欢迎在评论指出,也感谢@goozp提出的问题。

https://stackoverflow.com/questions/53588764/how-to-add-local-dependence-to-vendor-when-using-go-mod

https://www.cnblogs.com/apocelipes/p/9609895.html