1,071
社区成员




您可能已经注意到GO111MODULE=on
到处都在蓬勃发展。许多自述文件都有:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get golang.org/x/tools/gopls@latest
</code></span></span>
请注意,go get
自 Go 1.17 以来已弃用安装二进制文件,并且在 Go 1.18 中将变得不可能。如果您使用的是 Go 1.16 或更高版本,则应改用:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@latest
</code></span></span>
在这篇简短的文章中,我将解释为什么GO111MODULE
在 Go 1.11 中引入它,它的注意事项和在处理 Go 模块时需要了解的有趣信息。
表中的内容:
GOPATH
到GO111MODULE
GO111MODULE
变量
GO111MODULE
使用 Go 1.11 和 1.12GO111MODULE
使用 Go 1.13GO111MODULE
使用 Go 1.14GO111MODULE
使用 Go 1.15GO111MODULE
使用 Go 1.16GO111MODULE
使用 Go 1.17GO111MODULE=on go get
已弃用go run
知道@version
(终于!)GO111MODULE
使用 Go 1.18GO111MODULE
使用 Go 1.19GO111MODULE
使用 Go 1.20GO111MODULE
到处都是?(转到 1.15 及以下版本)go.mod
(Go 1.15及以下)-u
_ @version
_GOPATH
到GO111MODULE
首先,让我们谈谈 GOPATH。当 Go 在 2009 年首次推出时,它并没有附带包管理器。相反,go get
将使用它们的导入路径获取所有源并将它们存储在$GOPATH/src
. 没有版本控制,“master”分支代表包的稳定版本。
Go 模块(以前称为 vgo -- 版本化的 Go)是在 Go 1.11 中引入的。Go Modules 不是使用 GOPATH 来存储每个包的单个 git checkout,而是存储标记的版本并go.mod
跟踪每个包的版本。
从那时起,“GOPATH 行为”和“Go 模块行为”之间的交互已成为 Go 最大的问题之一。一个环境变量造成了 95% 的痛苦:GO111MODULE
.
GO111MODULE
变量GO111MODULE
go
是一个环境变量,可以在用于更改 Go 导入包的方式时设置。第一个痛点是,根据 Go 版本的不同,它的语义会发生变化。
GO111MODULE
可以通过两种不同的方式设置:
export GO111MODULE=on
.go env
只有使用才知道的“隐藏”全局配置go env -w GO111MODULE=on
(仅自 Go 1.12 起可用)。如果 Go 似乎按照您认为的方式运行,建议您检查过去是否使用go env -w GO111MODULE=on
(或off
)设置了全局配置:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">env </span>GO111MODULE
</code></span></span>
请注意,环境变量优先于使用存储的值go env -w GO111MODULE
。
要取消设置全局配置,您可以执行以下操作:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">env</span> <span style="color:var(--syntax-error-color)">-u</span> GO111MODULE
</code></span></span>
GO111MODULE
使用 Go 1.11 和 1.12GO111MODULE=on
即使项目在您的 GOPATH 中,也会强制使用 Go 模块。需要go.mod
工作。GO111MODULE=off
强制 Go 以 GOPATH 方式运行,即使在 GOPATH 之外。GO111MODULE=auto
是默认模式。在这种模式下,Go 将表现
GO111MODULE=on
当你在外面时GOPATH
,GO111MODULE=off
你在里面时,GOPATH
即使 ago.mod
存在。每当您在 GOPATH 中并且想要执行需要 Go 模块的操作(例如,go get
特定版本的二进制文件)时,您需要执行以下操作:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get github.com/golang/mock/tree/master/mockgen@v1.3.1
</code></span></span>
GO111MODULE
使用 Go 1.13使用 Go 1.13,GO111MODULE
默认 ( auto
) 更改:
GO111MODULE=on
都有OR ,go.mod
即使没有 go.mod
因此,您可以使用 Go 1.13 将所有存储库保存在您的 GOPATH 中。GO111MODULE=off
在没有go.mod
.GO111MODULE
使用 Go 1.14该GO111MODULE
变量具有与 Go 1.13 相同的行为。
请注意,与发生的行为无关的一些细微变化GO111MODULE
:
vendor/
。这有破坏 Gomock(问题)的趋势,它在 1.14 之前不知不觉地没有使用vendor/
。cd && GO111MODULE=on go get
当你不想弄乱你当前的项目时,你仍然需要使用它go.mod
(那太烦人了)。GO111MODULE
使用 Go 1.15GO111MODULE
Go 1.15没有任何改变。
GO111MODULE
使用 Go 1.16从 Go 1.16 开始,默认行为是GO111MODULE=on
,这意味着如果你想继续使用旧GOPATH
方法,你将不得不强制 Go 不使用 Go Modules 功能:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>off
</code></span></span>
Go 1.16 中最好的消息是我们终于得到了一个专门的命令来安装 Go 工具,而不是依赖于不断go get
更新你的go.mod
. 代替:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># Old way</span>
<span style="color:var(--syntax-error-color)">(</span><span style="color:var(--syntax-text-color)">cd</span> <span style="color:var(--syntax-error-color)">&&</span> go get golang.org/x/tools/gopls@latest<span style="color:var(--syntax-error-color)">)</span>
</code></span></span>
你现在可以运行:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@latest
</code></span></span>
需要注意的是, 的语义go install
与 略有不同go get
。如Go
博客中所述:
为了消除关于使用哪个版本的歧义,
go.mod
在使用此安装语法时,对程序文件中可能存在的指令有一些限制。特别是,替换和排除指令是不允许的,至少现在是这样。从长远来看,一旦新版本go install program@version
在足够多的用例中运行良好,我们计划停止go get
安装命令二进制文件。有关详细信息,请参阅问题 43684。
例如,您不能(截至 2021 年 4 月)安装gopls的主版本:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>% go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@master
go: downloading golang.org/x/tools v0.1.1-0.20210316190639-9e9211a98eaa
go: downloading golang.org/x/tools/gopls v0.0.0-20210316190639-9e9211a98eaa
go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@master: golang.org/x/tools/gopls@v0.0.0-20210316190639-9e9211a98eaa
The go.mod file <span style="color:var(--syntax-declaration-color)">for </span>the module providing named packages contains one or
more replace directives. It must not contain directives that would cause
it to be interpreted differently than <span style="color:var(--syntax-declaration-color)">if </span>it were the main module.
</code></span></span>
go.mod文件中的替换指令如下所示:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">replace</span> <span style="color:var(--syntax-text-color)">golang</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">org</span><span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-text-color)">tools</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-error-color)">../</span>
</code></span></span>
幸运的是,gopls 项目确保replace
在每次发布之前删除该指令,这意味着您可以使用latest
标签:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@latest
<span style="color:var(--syntax-comment-color)"># ^^^^^^</span>
</code></span></span>
GO111MODULE
使用 Go 1.17Go 1.17 于 2021 年 8 月 16 日发布。至于 1.16,GO111MODULE=on
是默认行为,GO111MODULE=auto
相当于GO111MODULE=on
. 如果你仍然想使用这种GOPATH
方式,你将不得不强制 Go 不使用 Go Modules 特性GO111MODULE=off
(参见关于 的部分direnv
)。
可能影响您使用方式的三个重要变化GO111MODULE
如下:
如果您使用 Git 获取模块,则可以更快地下载依赖项
如果您决定更新go
您的行go.mod
以利用新模块图形修剪,您go.mod
将希望得到更新。第一次使用 时go build
,您会看到以下错误:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go build ./...
go: updates to go.mod needed; to update it:
go mod tidy
</code></span></span>
运行后go mod tidy
,你会看到你的go.mod
新块发生了很大变化require
:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>diff --git a/go.mod b/go.mod
index 3af719e..26ed354 100644
<span style="color:var(--syntax-error-color)">--- a/go.mod
</span><span style="color:var(--syntax-name-color)">+++ b/go.mod
</span><span style="color:var(--syntax-text-color)">@@ -1,12 +1,12 @@</span>
module github.com/maelvls/users-grpc
-go 1.12
<span style="color:var(--syntax-name-color)">+go 1.17
</span>
require (
github.com/MakeNowJust/heredoc/v2 v2.0.1
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/golang/mock v1.4.4
<span style="color:var(--syntax-error-color)">- github.com/golang/protobuf v1.4.3
</span><span style="color:var(--syntax-name-color)">+ github.com/golang/protobuf v1.5.2
</span> github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/hashicorp/go-memdb v1.3.0
<span style="color:var(--syntax-text-color)">@@ -37,8 +37,25 @@</span> require (
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20201116205149-79184cff4dfe // indirect
google.golang.org/grpc v1.33.2
<span style="color:var(--syntax-error-color)">- google.golang.org/protobuf v1.25.0
</span><span style="color:var(--syntax-name-color)">+ google.golang.org/protobuf v1.27.1
</span> gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
)
<span style="color:var(--syntax-name-color)">+
+require (
+ github.com/beorn7/perks v1.0.0 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
+ github.com/hashicorp/golang-lru v0.5.4 // indirect
+ github.com/hashicorp/hcl v1.0.0 // indirect
+ github.com/inconshreveable/mousetrap v1.0.0 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
+ github.com/prometheus/common v0.4.0 // indirect
+ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ github.com/subosito/gotenv v1.2.0 // indirect
+ gopkg.in/yaml.v2 v2.3.0 // indirect
+)
</span></code></span></span>
新require
块添加了更多// indirect
行。多亏了这些新行,Go 命令的go get
下载量减少了(该机制称为惰性模块加载)。以前,go get
必须下载每个项目才能访问它们的go.mod
文件,即使其中一些项目实际上并未被您的代码使用。GOPROXY
这对于基于 git 的项目来说是个大问题,而对于使用该机制的人(即其他所有人)来说问题不大,因为go.mod
在使用该机制时无需获取整个存储库即可获取GOPROXY
。
例如,使用该GOPROXY
机制,使用标签 v1.4.0 的 cert-manager 项目,HTTP GET 调用的次数从 252 次减少到 169 次(减少 49% 的 HTTP 请求)。HTTP 调用的数量是使用 mitmproxy 计算的GOCACHE=off
。虽然 HTTP 调用的次数减少了,但我没有注意到任何显着的时间减少。
最大的不同将发生在依赖 Git 下载存储库的人身上。每次 Go 需要读取一个go.mod
,它需要下载整个 Git 存储库。我们可以使用以下命令强制 Go 克隆 Git 存储库GOPRIVATE=*
:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># With Go 1.16:</span>
<span style="color:var(--syntax-text-color)">$ </span><span style="color:var(--syntax-text-color)">time </span><span style="color:var(--syntax-text-color)">GOPATH</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">$(</span><span style="color:var(--syntax-text-color)">mktemp</span> <span style="color:var(--syntax-error-color)">-d</span><span style="color:var(--syntax-string-color)">)</span> <span style="color:var(--syntax-text-color)">GOPRIVATE</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">'*'</span> go get ./...
161.65s user 34.07s system 38% cpu 8:23.58 total
<span style="color:var(--syntax-comment-color)"># With Go 1.17:</span>
<span style="color:var(--syntax-text-color)">$ </span><span style="color:var(--syntax-text-color)">time </span><span style="color:var(--syntax-text-color)">GOPATH</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">$(</span><span style="color:var(--syntax-text-color)">mktemp</span> <span style="color:var(--syntax-error-color)">-d</span><span style="color:var(--syntax-string-color)">)</span> <span style="color:var(--syntax-text-color)">GOPRIVATE</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">'*'</span> go get ./...
158.09s user 33.39s system 39% cpu 7:59.63 total
</code></span></span>
这快了 5%(使用 30 Mbit/s DSL 连接时减少了 24 秒)。我本来期待更好的结果,但这个数字将取决于go.mod
你有!
安装二进制文件GO111MODULE=on go get
已弃用
在 Go 1.17 中,使用go get
安装二进制文件现在显示以下警告:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">$ GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get golang.org/x/tools/gopls@latest
go get: installing executables with <span style="color:var(--syntax-string-color)">'go get'</span> <span style="color:var(--syntax-declaration-color)">in </span>module mode is deprecated.
Use <span style="color:var(--syntax-string-color)">'go install pkg@version'</span> instead.
For more information, see https://golang.org/doc/go-get-install-deprecation
or run <span style="color:var(--syntax-string-color)">'go help get'</span> or <span style="color:var(--syntax-string-color)">'go help install'</span><span style="color:var(--syntax-text-color)">.</span>
</code></span></span>
要解决此警告,您可以使用Go 1.16 中go install
教授的处理方法:@version
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@latest
</code></span></span>
请注意,这@version
意味着 Go 模块模式,这意味着GO111MODULE=on
当您不在具有go.mod
.
go run
知道@version
(终于!)
该go run
命令被教导如何处理@version
!就像go install
,它暗示着GO111MODULE=on
。到目前为止,如果你想运行一次二进制文件,你有两种方法:
go.mod
,则可以指定要在您的项目中运行的二进制文件的版本go.mod
,然后运行go run -mod=mod
.
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code># Before Go 1.17:
go get github.com/golang/mock/mockgen@v1.3.1
go run -mod=mod github.com/golang/mock/mockgen
# With Go 1.17:
go run github.com/golang/mock/mockgen@v1.3.1
</code></span></span>
//go:generate
如果你用来生成模拟,这很好。例如,在项目users-grpc中,我能够替换我的//go:generate
指令:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// Old way, before 1.17:</span>
<span style="color:var(--syntax-comment-color)">//go:generate go run -mod=mod github.com/golang/mock/mockgen -build_flags=-mod=mod -package mocks -destination ./mock_service.go -source=../ user.go</span>
<span style="color:var(--syntax-comment-color)">// New way, Go 1.17:</span>
<span style="color:var(--syntax-comment-color)">//go:generate go run github.com/golang/mock/mockgen@v1.4.4 -package mocks -destination ./mock_service.go -source=../user.go</span>
</code></span></span>
GO111MODULE
使用 Go 1.18如果您仍需要使用go get
安装二进制文件,则需要设置GO111MODULE=off
. 推荐的方法是改为使用go install
。没有GO111MODULE=off
,go get
只会更新你的go.mod
。否则,它不会做任何事情。网上所有的README都要更新;如果他们不这样做,人们会因为看不到正在安装的二进制文件而感到困惑。
GO111MODULE
使用 Go 1.19GO111MODULE
Go 1.19没有任何改变。
GO111MODULE
使用 Go 1.20GO111MODULE
Go 1.20没有任何改变。
GO111MODULE
到处都是?(转到 1.15 及以下版本)现在我们知道这GO111MODULE
对于 Go 1.15 及以下版本对于启用 Go 模块行为非常有用,答案是:那是因为GO111MODULE=on
允许您选择一个版本。没有 Go Modules,go get
从 master 获取最新的提交。使用 Go Modules,您可以根据 git 标签选择特定版本。
GO111MODULE=on
在 Go 1.16 发布之前,当我想在最新版本和gopls
(Go 语言服务器)的 HEAD 版本之间切换时,我经常使用:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># With Go 1.15.</span>
<span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get golang.org/x/tools/gopls@latest
<span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get golang.org/x/tools/gopls@master
<span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get golang.org/x/tools/gopls@v0.1
<span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get golang.org/x/tools/gopls@v0.1.8
<span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"on"</span> go get sigs.k8s.io/kind@v0.7.0
</code></span></span>
不过在 Go 1.16 中这变得容易多了。我可以做同样的事情:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># With Go 1.16.</span>
go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@latest
</code></span></span>
go.mod
(Go 1.15及以下)对于 Go 1.15 及以下版本,我们安装二进制文件的唯一选择是使用go get
. 您可能在 README 中遇到过这种奇怪的单行代码:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-error-color)">(</span><span style="color:var(--syntax-text-color)">cd</span> <span style="color:var(--syntax-error-color)">&&</span> <span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get golang.org/x/tools/gopls@latest<span style="color:var(--syntax-error-color)">)</span>
</code></span></span>
注意:后缀
@latest
会使用gopls最新的git标签。请注意,-u
不需要(这意味着“更新”),@v0.1.8
因为这是一个“固定”版本,更新固定版本并没有真正意义。有趣的是,使用@v0.1
,go get
将获取该标签的最新补丁版本。
那么,为什么我们需要使用这个调用子 shell 并移动到您的 HOME 的人为命令?这是 Go 1.16 修复的另一个 Go 专制政治:在 Go 1.15 及以下版本中,默认情况下(你不能关闭它),如果你在一个有 的文件夹中,将用你刚刚安装的内容go.mod
更新go get
它go.mod
。对于像gopls或kind这样的开发二进制文件,您绝对不希望它们出现在go.mod
文件中!
因此,对于使用 Go 1.15 及以下版本的任何人来说,解决方法是提供一个单行代码,确保您不会在启用go.mod
-enabled 的文件夹中:(cd && go get)
正是这样做的。
幸运的是,在 Go 1.16 中,现在可以明确区分go get
添加依赖项go.mod
(如 npm install)和go install
安装二进制文件而不会弄乱你的go.mod
. 在 Go 1.16 中,上面的内容go get
变成了:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">install </span>golang.org/x/tools/gopls@latest
</code></span></span>
-u
_ @version
_我被这个困扰了很多次:使用时go get @latest
(至少对于二进制文件),你应该避免使用,-u
以便它使用go.sum
. 否则,它会将所有依赖项更新到它们最新的次要修订版……并且由于大量项目选择在次要版本(例如 v0.2.0 到 v0.3.0)之间进行重大更改,因此使用很有可能会造成破坏-u
。
所以如果你看到这个:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># Both -u and @latest!</span>
<span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on go get <span style="color:var(--syntax-error-color)">-u</span> golang.org/x/tools/gopls@latest
</code></span></span>
然后你会立即意识到(1)它使用旧的 preGo .1.16 方式安装 Go 二进制文件,并且(2)你想使用在go.sum
go-getting 二进制文件时给出的记录版本!
Rebecca Stambler提醒我们不要-u
与版本一起使用:
-u
不应与@latest
标签一起使用,因为它会给您不正确的依赖项版本。
但它有点隐藏在这个问题中......我猜它写在 Go 帮助的某个地方(顺便说一句,git help
与和?@version
_-u
现在,让我们回顾一下我在使用 Go 模块时遇到的一些注意事项。
go get
也会更新您的go.mod
在 Go 1.16 发布之前,这是一个奇怪的事情go get
:有时,它用于安装二进制文件或下载包。go.mod
对于 Go 模块,如果你在一个go get
带有go.mod
.
幸运的是,在 Go 1.16 中,go install
已经了解了后缀@version
。使用go install foo@version
,您的本地go.mod
不会受到影响!在 Go 1.18 中,go get
将不再安装二进制文件,只会用于向你的go.mod
.
如果你想运行go test
或go build
不go.mod
更新,你可以使用标志-mod=readonly
。例如:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>go <span style="color:var(--syntax-text-color)">test</span> <span style="color:var(--syntax-error-color)">-mod</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">readonly</span> ./...
go build <span style="color:var(--syntax-error-color)">-mod</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">readonly</span> ./...
</code></span></span>
使用 Go Modules 时,使用的包go build
存储在$GOPATH/pkg/mod
. 当尝试检查 vim 或 VSCode 中的“导入”时,您可能最终会看到包的 GOPATH 版本,而不是编译期间使用的 pkg/mod 版本。
出现的第二个问题是当您想破解您的依赖项之一时,例如出于测试目的。
解决方案 1:使用go mod vendor
+ go build -mod=vendor
。这将强制go
使用 vendor/ 文件而不是使用那些$GOPATH/pkg/mod
文件。此选项还解决了 vim 和 VSCode 无法打开包文件的正确版本的问题。
解决方案 2:在您的末尾添加“替换”行go.mod
:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>replace github.com/maelvls/beers => ../beers
</code></span></span>
../beers
我要检查和破解的依赖项的本地副本在哪里。
GO111MODULE
在每个文件夹的基础上 设置direnv
在旧版本的 Go(1.15 及更低版本)上,从基于 GOPATH 的项目(主要使用 Dep)迁移到 Go Modules 时,我发现自己在两个不同的地方挣扎:GOPATH 内部和外部。所有 Go 模块都必须保存在 GOPATH 之外,这意味着我的项目位于不同的文件夹中。为了解决这个问题,我GO111MODULE
广泛使用了。我会把我所有的项目都放在 GOPATH 中,对于支持 Go Modules 的项目,我会设置export GO111MODULE=on
.
注意:由于 Go 1.16 中的默认行为现在是
GO111MODULE=on
,因此不再需要此技巧。
这是direnv
派上用场的地方。Direnv 是一个用 Go 编写的轻量级命令,它会.envrc
在您进入一个目录并且.envrc
存在时加载一个文件。对于每个支持 Go Module 的项目,我都会有这个.envrc
:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># .envrc</span>
<span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">GO111MODULE</span><span style="color:var(--syntax-error-color)">=</span>on
<span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">GOPRIVATE</span><span style="color:var(--syntax-error-color)">=</span>github.com/mycompany/<span style="color:var(--syntax-literal-color)">\*</span>
<span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">GOFLAGS</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-error-color)">-mod</span><span style="color:var(--syntax-error-color)">=</span>vendor
</code></span></span>
环境GOPRIVATE
变量禁用某些导入路径的 Go 代理(在 Go 1.13 中引入)。我还发现设置有用,-mod=vendor
以便每个命令都使用vendor
文件夹 ( go mod vendor
)。
许多公司选择使用私有存储库作为导入路径。如上所述,我们可以使用GOPRIVATE
命令告诉 Go(从 Go 1.13 开始)跳过包代理并直接从 Github 获取我们的私有包。
但是如何构建 Docker 镜像呢?如何go get
从 docker 构建中获取我们的私有存储库?
解决方案 1:销售
使用go mod vendor
,无需将 Github 凭据传递给 docker 构建上下文。我们可以把所有东西都放进去vendor/
,问题就解决了。在 Dockerfile 中,-mod=vendor
将是必需的,但开发人员甚至不必费心,-mod=vendor
因为他们无论如何都可以使用本地 Git 配置访问私有 Github 存储库
vendor/
更改而臃肿,回购的大小可能很大解决方案 2:无销售
如果vendor/
太大(例如,对于 Kubernetes 控制器,vendor/
大约 30MB),我们可以很好地完成它而无需 vendoring。这将需要传递某种形式的 GITHUB_TOKEN 作为参数docker build
,并在 Dockerfile 中设置如下内容:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>git config <span style="color:var(--syntax-error-color)">--global</span> url.<span style="color:var(--syntax-string-color)">"https://foo:</span><span style="color:var(--syntax-declaration-color)">${</span><span style="color:var(--syntax-text-color)">GITHUB_TOKEN</span><span style="color:var(--syntax-declaration-color)">}</span><span style="color:var(--syntax-string-color)">@github.com/company"</span>.insteadOf <span style="color:var(--syntax-string-color)">"https://github.com/company"</span>
<span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">GOPRIVATE</span><span style="color:var(--syntax-error-color)">=</span>github.com/company/<span style="color:var(--syntax-literal-color)">\*</span>
</code></span></span>
use replace
不仅仅是replace
.go env GO111MODULE
报告的问题。