使用 "go get" 下载二进制文件而不将它们添加到 go.mod

Using "go get" to download binaries without adding them to go.mod

我在我的项目和我的构建系统中使用 Go 模块(例如 Travis CI)我正在下载一个命令行实用程序(用 Go 编写)go get 来协助使用我的构建过程,例如:

go get github.com/mitchellh/gox

但是,这 go get 导致文件被添加到我的 go.mod 文件中。这污染了构建环境,导致它成为 "dirty"(因为在 git 中跟踪了一些文件的更改,在本例中为 go.mod 和 go.sum),并且我使用 git describe --always --dirty --tag 描述我的构建,显示为 "dirty".

有没有办法 "go get" 只下载一个二进制文件,而无需将其添加到 go 中。mod/go.sum?

我已经尝试将 GOPATH 设置到其他地方,即使那样,go get 也会更新 go.mod/go.sum 以将其添加为 // indirect 依赖项。

dir="$(mktemp -d)"; \
  env GOPATH="$dir" go get github.com/mitchellh/gox && \
  mv "$dir/bin/gox" "$(go env GOPATH)"/bin/gox

go help build:

The -mod build flag provides additional control over updating and use of go.mod.

If invoked with -mod=readonly, the go command is disallowed from the implicit automatic updating of go.mod

希望在 Go 1.14 中会有一个 go get 的新标志,它完全符合您的要求。这在问题 #30515 "cmd/go: offer a consistent global install command".

中进行了跟踪

在此之前,您有几个不同的选择。

转到 1.12 和 1.13:更改目录

如果您使用的是 Go 1.12 或更高版本,最简单的解决方案可能是在执行 go get 之前将当前模块移出到一个没有 go.mod 的目录,例如:

$ cd /tmp                              
$ go get github.com/foo/bar@v1.2.3
$ cd -                                # return to prior directory

Go 1.11、1.12、1.13+:gobin

gobin is a module-aware command to install or run binaries that provides additional flexibility, including the ability to install without altering your current module's go.mod. See the gobin README and FAQ了解更多详情。

Go 1.11:临时模块

如果您使用带有模块的 Go 1.11,第一步可能是升级到 Go 1.12 或 1.13,因为模块有很多改进。如果您需要使用 Go 1.11 并且想使用 @version 语法而不更新当前模块的 go.mod,那么一种方法是创建一个临时模块:

cd $(mktemp -d) && go mod init tempmod && go get github.com/foo/bar@v1.2.3

这是因为在 Go 1.11 中,除非在模块中,否则不能使用 @version 语法,这在 Go 1.12 中放宽了。 simple shell script by @rogpeppe.

已将此方法自动化

其他详细信息

一般来说,module-module中的go命令总是会根据调用go命令时的当前工作目录来判断它是什么模块"in"。 (您可以类比没有任何参数的 make 如何在当前工作目录中查找 makefile,或者历史上没有任何参数的 go build 将如何构建当前工作目录等)。

对于模块,go get 在当前工作目录或其任何父目录中查找 go.mod 文件,并且 go get 将使用任何 [=13= 中列出的约束] 作为解决版本问题的一部分,并在需要时根据 go get 更新 go.mod。这就是为什么如果您从现有模块中 运行 go get 更新您的 go.mod 文件。

另一方面,从 Go 1.12 开始,如果您所在的目录不属于任何模块(也就是说,该目录没有 go.mod,它的任何父目录也没有),则没有go.mod更新,但go命令仍然可以在模块模式下运行并使用@version语法。

来自Go 1.12 release notes

When GO111MODULE is set to on, the go command now supports module-aware operations outside of a module directory, provided that those operations do not need to resolve import paths relative to the current directory or explicitly edit the go.mod file. Commands such as go get, go list, and go mod download behave as if in a module with initially-empty requirements. In this mode, go env GOMOD reports the system's null device (/dev/null or NUL).

从 1.16 开始

Go 1.16(2021 年 2 月发布)包含一项更改,可以在不影响 go.mod.

的情况下安装二进制文件

Issue 40276跟踪提案:

cmd/go: 'go install' should install executables in module mode outside a module

这是在 CL 254365 中实现的。作为此更改的一部分,您可以 运行 例如:

go install golang.org/x/tools/cmd/goimports@latest

在不影响 go.mod 的情况下安装二进制文件。

要安装特定版本,请将 @latest 替换为例如@v0.1.5.