Go 1.11包括此处建议的对版本模块的初步支持。模块是Go 1.11中的实验性加入功能,并计划纳入反馈并最终确定 Go 1.14中的功能。即使某些细节可能会更改,将来的发行版也将支持使用Go 1.11、1.12和1.13定义的模块。

vgo

请通过现有问题或新问题以及经验报告提供有关模块的反馈。

近期变动

Go 1.13中对模块进行了重大改进和更改。

如果使用模块,请务必仔细阅读Go 1.13发行说明的模块部分。

三个值得注意的变化:

goGO111MODULE=autoGO111MODULE=autogo getgo get -ugo get -u ./...go get -u -t ./...go get-mgo get -dgo get -m foogo get -d foo

请参阅发行说明,以获取有关这些更改和其他更改的更多详细信息。

 

快速开始

详细信息将在本页面的其余部分中介绍,但这是一个从头开始创建模块的简单示例。

在GOPATH之外创建目录,并可选地初始化VCS:

$ mkdir -p /tmp/scratchpad/repo
$ cd /tmp/scratchpad/repo
$ git init -q
$ git remote add origin https://github.com/my/repo

初始化一个新模块:

$ go mod init github.com/my/repo

go: creating new go.mod: module github.com/my/repo

编写代码:

$ cat <<EOF > hello.go
package main

import (
    "fmt"
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}
EOF

构建并运行:

$ go build -o hello
$ ./hello

Hello, world.
go.modv1.5.2
$ cat go.mod

module github.com/my/repo

require rsc.io/quote v1.5.2

日常工作流程

go get

典型的日常工作流程可以是:

.gogo buildgo testgo.modgo get foo@v1.2.3go get foo@masterfoo@tipgo get foo@e3702bed2go.mod

您可能会使用的其他常见功能的简要介绍:

在阅读了有关“新概念”的下四个部分之后,您将获得足够的信息来开始使用大多数项目的模块。查看上面的目录(包括此处的FAQ常见问题解答)以使自己熟悉更详细的主题列表也很有用。

新概念

这些部分对主要的新概念进行了高级介绍。有关更多详细信息和原理,请观看Russ Cox的这段40分钟的介绍性视频,其中介绍了设计背后的理念,正式的建议文档或更为详细的初始vgo博客系列。

模组

一个模块是被一起版本作为单个单元相关的围棋包的集合。

模块记录精确的依赖要求并创建可复制的构建。

通常,版本控制存储库仅包含在存储库根目录中定义的一个模块。(单个存储库中支持多个模块,但是通常,与每个存储库中的单个模块相比,这将导致正在进行的工作更多)。

总结存储库,模块和软件包之间的关系:

  • 一个存储库包含一个或多个Go模块。
  • 每个模块包含一个或多个Go软件包。
  • 每个软件包都在一个目录中包含一个或多个Go源文件。
v(major).(minor).(patch)v0.1.0v1.2.3v1.5.0-rc.1v

go.mod

go.modmodulerequirereplaceexclude
go.modgithub.com/my/thing
module github.com/my/thing

require (
    github.com/some/dependency v1.2.3
    github.com/another/dependency/v4 v4.0.0
)
go.modmodulego.mod
github.com/my/repogithub.com/my/repo/foogithub.com/my/repo/bargo.modmodule github.com/my/repo
repo
|-- bar
|   `-- bar.go
|-- foo
|   `-- foo.go
`-- go.mod
go.modmodule example.com/my/module
import "example.com/my/module/mypkg"
mypkgexample.com/my/module
excludereplaceexcludereplacereplaceexcludereplace

版本选择

requirego.modgo.modrequirev1.2.3go.modrequire M v1.2.3
require
require D v1.0.0require D v1.1.1v1.1.1requirev1.1.1v1.2.0
vgo
go list -m all

另请参见下面的“如何升级和降级依赖项”部分和“如何将版本标记为不兼容?” 下面的常见问题解答。

语义导入版本控制

多年以来,官方的Go常见问题解答已在软件包版本管理中包括以下建议:

最后一句特别重要-如果破坏兼容性,则应更改软件包的导入路径。使用Go 1.11模块,该建议被正式化为导入兼容性规则

当v1或更高版本的软件包进行向后不兼容的更改时,召回semver需要对主要版本进行更改。遵循导入兼容性规则和semver的结果称为语义导入版本控制,其中主要版本包含在导入路径中-这可确保在主要版本由于兼容性中断而增加时,导入路径都会更改。

由于语义导入版本控制,选择加入Go模块的代码必须遵守以下规则:

v1.2.3/vNgo.modmodule github.com/my/mod/v2require github.com/my/mod/v2 v2.0.1import "github.com/my/mod/v2/mypkg"go getgo get github.com/my/mod/v2@v2.0.1/v2@v2.0.1/v2/v2
math/randcrypto/randexample.com/my/mod/mypkgexample.com/my/mod/v2/mypkg
go

到目前为止,本节的重点是已选择加入模块并导入其他模块的代码。但是,将主要版本置于v2 +模块的导入路径中可能会与Go的较早版本或尚未选择加入模块的代码产生不兼容性。为了解决这个问题,上述行为和规则有三种重要的过渡性特殊情况或例外。随着越来越多的程序包加入模块,这些过渡性异常将不再重要。

三个过渡例外

有关发布v2 +模块所需的确切机制,请参阅下面的“发布模块(v2或更高版本)”部分。

如何使用模块

如何安装和激活模块支持

要使用模块,两个安装选项是:

安装后,您可以通过以下两种方式之一激活模块支持:

go$GOPATH/srcgo.modGO111MODULEautogoGO111MODULE=on

如何定义模块

go.mod

在标记发行版之前,请参见下面的“如何准备发行版”部分。

有关所有这些主题的更多信息,可在golang.org上找到官方模块文档的主要入口点。

如何升级和降级依赖项

go.modgo.mod
go.mod
go list -u -m all

要将当前模块的所有直接和间接依赖关系升级到最新版本,可以在模块根目录中运行以下命令:

go get -u ./...-tgo get -u=patch ./...-t
go get foofoogo get foogo get foo@latest@latest@

在本节中,“最新”是带有semver标签的最新版本,或者如果没有semver标签则是最新的已知提交。除非存储库中没有其他semver标签,否则不会将预发布标签选择为“最新”标签(details)。

go get -u foofoo-ugo get -u foogo get -u foo@latestfoofoogo get foogo get foo@latest-ugo get -u=patch foogo get -u=patchgo get -u foogo get -u
go get foo@v1.6.2go get foo@e3702bed2go get foo@'
go get foo@masterfoo@tip
go.mod
go
go.modgo.mod

在升级或降级任何依赖项之后,您可能想要对构建中的所有软件包(包括直接和间接依赖项)再次运行测试以检查不兼容性:

$ go test all

如何准备发布

发行模块(所有版本)

创建模块发行版的最佳实践有望作为初始模块实验的一部分出现。其中许多最终可能会由将来的“发布”工具自动化。

在标记版本之前,应考虑一些当前建议的最佳做法:

go mod tidygo buildgo testgo.modgo.modgo test allgo test allgo.sumgo.mod

发行模块(v2或更高版本)

如果要发布v2或更高版本的模块,请首先查看上面“语义导入版本控制”部分中的讨论,其中包括为何在v2 +模块的模块路径和导入路径中包含主要版本以及Go版本1.9的方式.7+和1.10.3+已更新,以简化该过渡。

v2.0.0foofoov2.2.2foov3.0.0foofoogo.modfoofoofooimport "foo"require foo v2.2.2+incompatibleimport "foo/v3"require foo/v3 v3.0.0
v3.0.0
go.mod/v3modulemodule github.com/my/module/v3/v3import "github.com/my/module/v3/mypkg"v3.0.0v3my/module/v3go.mod/v3v3/v3import "github.com/my/module/v3/mypkg"v3.0.0goforwardgoforwarddep

有关这些替代方案的更深入讨论,请参见https://research.swtch.com/vgo-module。

发布发行

可以通过将标签推送到包含模块源代码的资源库中来发布新的模块版本。标签是通过串联两个字符串形成的:前缀版本

版本是该发行的语义导入版本。应该按照语义导入版本控制规则进行选择。

所述前缀指示其中模块的存储库中定义的。如果模块是在存储库的根目录中定义的,则前缀为空,而标记仅为版本。但是,在多模块存储库中,前缀区分不同模块的版本。前缀是存储库中定义模块的目录。如果存储库遵循上述主要子目录模式,则前缀不包括主要版本后缀。

example.com/repo/sub/v2v2.1.6example.com/reposub/v2/go.modsub/sub/v2.1.6

迁移到模块

本节试图简要列举迁移到模块时要做出的主要决定,并列出其他与迁移相关的主题。通常会提供其他部分的参考,以获取更多详细信息。

该材料主要基于模块实验中社区中出现的最佳实践。因此,这是一个进行中的部分,随着社区获得更多的经验,该部分将有所改善。

摘要:

  • 该模块系统旨在允许整个Go生态系统中的不同软件包以不同的速率选择加入。
  • 主要由于语义导入版本控制的影响,已经在版本v2或更高版本上的软件包具有更多的迁移注意事项。
  • 在采用模块时,新软件包和v0或v1上的软件包的考虑要少得多。
  • 使用Go 1.11定义的模块可以用于较旧的Go版本(尽管确切的Go版本取决于主模块使用的策略及其依赖项,如下所述)。

迁移主题:

从先前的依赖管理器自动迁移

向Go和非模块消费者的较旧版本提供依赖信息

更新现有安装说明

go get -u foofoo-u-ugofoogo get -u foo-ugo get -u foogo get fooimport "foo"go buildgo testfoogo.modvendorgo get foo/...

避免破坏现有的导入路径

go.modmodulemodule github.com/my/modulegounexpected module path

在为一组预先存在的软件包采用模块时,应注意避免破坏现有使用者使用的现有导入路径,除非在采用模块时增加主版本。

import "gopkg.in/foo.v1"go.modmodule gopkg.in/foo.v1gopkg.inmodule github.com/repo/foo/v2
github.com/Sirupsen/logrusgithub.com/sirupsen/logrus
go.mod
go.uber.org/zapgithub.com/uber-go/zap
package zap // import "go.uber.org/zap"

go.mod文件的module语句已淘汰了导入路径注释。

首次采用带有v2 +软件包的模块时增加主要版本

v2 +模块允许在一个内部版本中使用多个主要版本

foofoo/v3foofoo/v3init

消耗非模块代码的模块

非模块代码消费模块

  • 非模块代码消耗v0和v1模块:

    • 尚未选择使用模块的代码可以使用和构建v0和v1模块(与使用的Go版本无关)。
  • 非模块代码消耗v2 +模块:

预先存在的v2 +软件包作者的策略

对于考虑加入模块的预先存在的v2 +软件包的作者,总结替代方法的一种方法是在三种顶级策略之间进行选择。每个选择都有后续的决定和变化(如上所述)。这些替代的顶级策略是:

其他资源

文件和建议

go help modulesgo helpgo help modgo modgo help module-getgo getgo help goproxyfile:///vgovgo

入门资料

附加材料

  • Todd Keech的博客文章“ Go Modules and CircleCI”(2018年7月30日)
  • 博客文章“已接受vgo提案。现在如何?” 通过Russ Cox(2018年5月29日)
    • 包含有关版本模块当前是实验性选择功能的含义的摘要
  • 卡洛琳·范·史莱克(Carolyn Van Slyck)撰写的有关如何从头开始构建go并开始使用go模块的博客文章(2018年7月16日)

自最初的Vgo提案以来的变化

作为提案,原型和Beta版流程的一部分,整个社区创建了400多个问题。请继续提供反馈。

以下是一些较大的更改和改进的部分列表,其中几乎所有更改和改进都主要基于社区的反馈:

GitHub问题

常见问题

版本如何标记为不兼容?

requiredepcargoexcludereplace

版本模块建议的主要目标之一是为工具和开发人员在Go代码的版本周围添加通用词汇和语义。这为将来声明不兼容的其他形式奠定了基础,例如:

什么时候出现旧行为与新的基于模块的行为?

通常,模块是Go 1.11的可选组件,因此,根据设计,默认情况下会保留旧的行为。

总结何时获得旧的1.10现状行为与新的基于选择加入模块的行为:

go.modautoonoff
go getcannot find main module
GO111MODULE=ongo.modgo get
GO111MODULEGO111MODULE=auto
go.modgo.modgo getGO111MODULE=ongo getcannot find main modulego.mod

解决方案的替代方案包括:

GO111MODULEGO111MODULE=autogo getcannot find main moduleGO111MODULE=ongo getGO111MODULE=off go get example.com/cmdalias oldget='GO111MODULE=off go get'go.modvgoget example.com/cmd[@version]cannot use path@version syntax in GOPATH modegobingobin-mgobingo.mod~/global-tools/go.modcdgo getgo installgo.mod~/tools/gorename/go.mod~/tools/goimports/go.modcdgo getgo install

该当前限制将得到解决。但是,主要问题是模块当前处于启用状态,完整的解决方案可能要等到GO111MODULE = on成为默认行为。有关更多讨论,请参见#24250,包括此评论:

该常见问题解答一直在讨论跟踪全局安装的工具。

相反,如果要跟踪特定模块所需的工具,请参阅下一个FAQ。

如何跟踪模块的工具依赖关系?

如果你:

stringergo.mod
tools.goimport _ "golang.org/x/tools/cmd/stringer"// +build toolsgogo.mod// +build tools

有关如何执行此操作的具体示例,请参见本“通过示例执行模块”演练。

#25922中的此注释中讨论了该方法以及更早的具体示例。

简要理由(同样来自#25922):

IDE,编辑器和标准工具(例如goimports,gorename等)中模块支持的状态如何?

对模块的支持已开始在编辑器和IDE中获得。

例如:

在雨伞问题中一直跟踪其他工具(例如goimports,guru,gorename和类似工具)的状态#24661。请查看该伞的最新状态。

特定工具的一些跟踪问题包括:

go mod vendor
go/buildgolang.org/x/tools/go/packagesgo/packages

常见问题解答-附加控制

存在哪些社区工具来使用模块?

社区开始在模块之上构建工具。例如:

replacegohack example.com/some/dependencyreplacego.modgohack undogo.modmgit -tag +0.0.1vendor/

什么时候应该使用replace指令?

replacego.modreplace
replacereplace
replace
replace example.com/some/dependency => example.com/some/dependency v1.2.3
replace
replace example.com/some/dependency => example.com/some/dependency-fork v1.2.3
go.mod
replace example.com/original/import/path => /your/forked/import/path
replace
replace example.com/project/foo => ../foo
replacego.modgo.modgo mod init
=>replace
requirereplacefooreplace foo => ../foorequirefoorequirev0.0.0require foo v0.0.0
go list -m allreplace

有关更多详细信息,请参见“ go mod edit”文档。

github.com/rogpeppe/gohack使这些类型的工作流变得更加容易,尤其是如果您的目标是对模块依赖项进行可变签出时。有关概述,请参见存储库或之前的常见问题解答。

replace

我可以在本地文件系统上完全不在VCS上工作吗?

是。不需要VCS。

go.modgo buildgo testreplacego.mod
replacego.modreplacehellogoodbye
module example.com/me/hello

require (
  example.com/me/goodbye v0.0.0
)

replace example.com/me/goodbye => ../goodbye
v0.0.0requirerequirerequire

该线程中显示了一个小的可运行示例。

如何对模块使用供应商?供应商会消失吗?

vgo

简而言之,要对模块使用供应商:

go mod vendorgo build-mod=vendorgo build -mod=vendorGOFLAGS=-mod=vendor
go mod vendor

如果您正在考虑使用供应商,则值得阅读技巧文档中的“模块和供应商”和“提供依赖关系的供应商副本”部分。

是否存在“始终在线”的模块存储库和企业代理?

公共托管的“始终在”不可变模块存储库以及可选的私有托管的代理和存储库正变得可用。

例如:

请注意,您不需要运行代理。相反,1.11中的go工具已通过GOPROXY添加了可选的代理支持,以启用更多企业用例(例如,更好的控制),并更好地处理诸如“ GitHub停机”或人们删除GitHub存储库的情况。

我可以控制go.mod何时更新以及go工具何时使用网络满足依赖关系吗?

go build
go.mod
-mod=readonly-mod=vendorGOFLAGSGOPROXY=offGOPROXY=file:///filesystem/pathgo mod vendorgo mod download

这些选项的详细信息遍布整个官方文档。此处是一个社区,试图对与这些行为相关的旋钮进行综合概述,其中包括指向官方文档的链接,以获取更多信息。

如何将模块与Travis或CircleCI等CI系统一起使用?

GO111MODULE=on

但是,由于您的某些用户尚未选择加入模块,因此在启用和禁用模块的Go 1.11上的CI中运行测试可能很有价值。供应商也是要考虑的话题。

以下两个博客文章更具体地介绍了这些主题:

常见问题解答— go.mod和go.sum

为什么“ go mod tidy”在我的“ go.mod”中记录间接和测试依赖项?

go.mod
go mod tidygo.mod
go mod tidygo.modgo buildgo testgo.modGOOSGOARCHgo mod tidygo build
go.modgo.modgo mod tidy// indirect
go.modgo test allgo test allgo test all
// indirectgo.modgo get -ugo get foo@1.2.3go.modgo.mod

通常,上述行为是模块如何通过记录精确的依赖项信息来提供100%可复制的构建和测试的一部分。

go.modgo mod why -m go mod graphgo list -m all

'go.sum'是锁定文件吗?为什么“ go.sum”包含有关我不再使用的模块版本的信息?

go.sumgo.mod
go.sumgo.sumgo.sum
go.sum
go.sumgo.sumgo.mod

我是否应该提交“ go.sum”文件以及“ go.mod”文件?

go.sumgo.mod
go.sumgo.sumgo mod verifygo.sumgo.sumgo.modgo.sum

如果我没有任何依赖关系,还应该添加一个“ go.mod”文件吗?

modulego.mod

常见问题解答—语义导入版本控制

为什么主版本号必须出现在导入路径中?

请参阅上面的“语义导入版本控制”概念部分中有关语义导入版本控制和导入兼容性规则的讨论。另请参阅宣布提案的博客文章,其中更多地讨论了导入兼容性规则的动机和理由。

为什么导入路径中省略了主要版本v0,v1?”

请参阅问题“为什么导入路径中省略了主要版本v0,v1?” 在较早的FAQ中,来自官方提案的讨论。

用主要版本v0,v1标记我的项目,或使用v2 +进行重大更改有什么含义?

在回应有关“ k8发行次要版本,但在每个次要版本中更改Go API”的评论时,Russ Cox做出以下回应,着重强调了选择v0,v1与频繁使用v2,v3,v4进行重大更改的一些含义。 ,等等。

与此相关的是,Kubernetes具有一些非典型的构建方法(当前在Godep之上包括自定义包装脚本),因此Kubernetes对于许多其他项目来说是不完善的示例,但是随着Kubernetes向采用Go 1.11迈进,这可能是一个有趣的示例。模块。

模块可以使用未选择模块的软件包吗?

是。

vgo getgo.mod v0.0.0-20171006230638-a6e239ea1c69go.mod
foov1.2.3foogo get foogo get foo@v1.2.3go.mod
require  foo  v1.2.3
gogo list -u=patchgo list -u -m all

有关尚未选择模块的v2 +软件包的更多详细信息,请参见下一个常见问题解答。

一个模块可以使用未选择模块的v2 +软件包吗?“ +不兼容”是什么意思?

+incompatible

额外细节

请熟悉上面“语义导入版本控制”部分中的材料。

首先回顾一些通常有用但在考虑本FAQ中描述的行为时要记住的特别重要的核心原则会有所帮助。

goGO111MODULE=on
/vNmodule foo/v2go.mod
gogo
+incompatible
/vN
go+incompatiblego

假设:

oldpackageoldpackagego.modoldpackagev3.0.1
go get oldpackage@latestgo.mod
require  oldpackage  v3.0.1+incompatible
/v3oldpackagego getrequire/vNoldpackageoldpackagego.modoldpackageoldpackagev3.0.1oldpackage/vNoldpackage
+incompatiblev3.0.1oldpackagev3.0.1oldpackagegov3.0.1oldpackageoldpackagev3.0.1oldpackage+incompatiblego
v3.0.1oldpackagev1.0.0v2.0.0v3.0.1
import  "oldpackage"
/v3oldpackage
v1.0.0v2.0.0v3.0.1oldpackageoldpackageoldpackagerequire
v4.0.0oldpackagego.modoldpackage/v4
import  "oldpackage/v4"

该版本将记录为:

require  oldpackage/v4  v4.0.0
oldpackage/v4oldpackageimport "oldpackage/v4"import "oldpackage"oldpackage/v4oldpackage/v5

如果未启用模块支持,如何在版本中处理v2 +模块?1.9.7 +,1.10.3 +和1.11中的“最小模块兼容性”如何工作?

在考虑尚未加入模块的较旧的Go版本或Go代码时,语义导入版本控制具有与v2 +模块相关的显着向后兼容性含义。

/vNgo.mod/vN

但是,预计生态系统将以不同的采用模块和语义导入版本控制的速度进行。

mymodule/v2mymodule/v3import "mymodule/v2/mypkg"
/vNgo.modmaster

为了在当前过渡时期提供帮助,Go 1.11 引入了“最小模块兼容性” ,以为尚未加入模块的Go代码提供更大的兼容性,并且“最小模块兼容性”也被反向移植到Go 1.9。 7和1.10.3(鉴于那些旧版Go版本不具有完整模块支持,这些版本始终在禁用完整模块模式的情况下始终有效运行)。

“最小模块兼容性”的主要目标是:

/vN/vN/vN

其他详细信息–“最小模块兼容性”

goGO111MODULE=off
/v2/vN
gofooimport "foo"foo/vN/vN.gogo.modimport "foo/v2"import "foo"/v2foo/v2gogo getgo list/vNimport "foo/v2"import "foo"fooimport "foo/v2"gogofooimport "foo"fooimport "foo/v2"foo

如果我创建go.mod但不将semver标记应用于存储库,会发生什么情况?

v0.1.0v1.2.3-rc.1
go

模块可以依赖于其自身的不同版本吗?

一个模块可以依赖于其自身的不同主要版本:总的来说,这相当于依赖于不同的模块。出于各种原因,这可能很有用,包括允许将模块的主要版本实现为围绕其他主要版本的填充程序。

此外,一个模块可以在一个周期中依赖于其自身的不同主要版本,就像两个完全不同的模块可以在一个周期中彼此​​依赖一样。

/v3

如果您惊讶地看到一个模块依赖于其自身的不同版本,那么值得回顾一下上面的“语义导入版本控制”部分以及常见问题解答“如果我没有看到预期的版本,该怎么办?依赖?” 。

两个程序包可能在一个周期中彼此​​不依赖仍然是一个约束。

FAQS —多模块存储库

什么是多模块存储库?

多模块存储库是一个包含多个模块的存储库,每个模块都有自己的go.mod文件。每个模块均从包含其go.mod文件的目录开始,并递归包含该目录及其子目录中的所有程序包,但不包括包含另一个go.mod文件的任何子树。

每个模块都有自己的版本信息。存储库根目录下的模块的版本标签必须包含相对目录作为前缀。例如,考虑以下存储库:

my-repo
`-- foo
    `-- rop
        `-- go.mod

模块“ my-repo / foo / rop”的1.2.3版本的标签是“ foo / rop / v1.2.3”。

通常,存储库中一个模块的路径将是其他模块的前缀。例如,考虑以下存储库:

my-repo
|-- bar
|-- foo
|   |-- rop
|   `-- yut
|-- go.mod
`-- mig
    |-- go.mod
    `-- vub

图。顶级模块的路径是另一个模块的路径的前缀。

该存储库包含两个模块。但是,模块“ my-repo”是模块“ my-repo / mig”的路径的前缀。

我应该在一个存储库中有多个模块吗?

在这样的配置中添加模块,删除模块和版本控制模块需要相当的谨慎和考虑,因此,管理单个模块存储库而不是现有存储库中的多个模块几乎总是更容易,更简单。

拉斯·考克斯(Russ Cox)在#26664中评论:

关于如何使多模块更有效的两个示例:

go test ./...replace

但是,除了这两个示例之外,还有其他细微差别。如果您考虑在单个存储库中包含多个模块,请仔细阅读本小节中的FAQ 。

go.mod
examples_examplesgo.modapiclientapigo.modclientapi

但是,对于这两种情况,如果您考虑为多组间接依赖项创建性能或下载大小的多模块存储库,则强烈建议您首先尝试使用GOPROXY,它将在Go中默认启用1.13。使用GOPROXY通常等同于可能会因创建多模块存储库而带来的任何性能优势或依赖项下载大小优势。

是否可以将模块添加到多模块存储库?

是。但是,此问题有两类:

第一类:要添加模块的软件包尚未处于版本控制中(新软件包)。这种情况很简单:将包和go.mod添加到同一提交中,标记该提交,然后推送。

第二类:添加模块的路径在版本控制中,并且包含一个或多个现有软件包。这种情况需要相当多的护理。为了说明,再次考虑以下存储库(现在位于github.com位置,以更好地模拟真实世界):

github.com/my-repo
|-- bar
|-- foo
|   |-- rop
|   `-- yut
|-- go.mod
`-- mig
    `-- vub

考虑添加模块“ github.com/my-repo/mig”。如果要采用与上述相同的方法,则可以通过两个不同的模块提供软件包/ my-repo / mig:旧版本的“ github.com/my-repo”和新的独立模块“ github”。 com / my-repo / mig。如果两个模块都处于活动状态,则导入“ github.com/my-repo/mig”将在编译时导致“模棱两可的导入”错误。

解决此问题的方法是使新添加的模块取决于“雕刻”出的模块,然后再将其雕刻出来。

假设“ github.com/my-repo”当前位于v1.2.3,让我们通过上面的存储库逐步进行操作:

cd path-to/github.com/my-repo/mig
go mod init github.com/my-repo/mig

# Note: if "my-repo/mig" does not actually depend on "my-repo", add a blank
# import.
# Note: version must be at or after the carve-out.
go mod edit -require github.com/myrepo@v1.3
cd path-to/github.com/my-repo/mig
go mod edit -replace github.com/my-repo@v1.3.0=../
go test ./...
go mod edit -dropreplace github.com/my-repo@v1.3.0

请注意,将来golang.org/issue/28835应该使测试步骤更直接。

还要注意,在次要版本之间,代码已从模块“ github.com/my-repo”中删除。不将其视为主要更改似乎很奇怪,但是在这种情况下,传递性依存关系继续在其原始导入路径中提供已删除软件包的兼容实现。

是否可以从多模块存储库中删除模块?

是的,具有与上述相同的两种情况和类似的步骤。

一个模块可以依赖于内部模块吗?

是。一个模块中的程序包可以从另一个模块中导入内部程序包,只要它们共享与内部/路径组件相同的路径前缀即可。例如,考虑以下存储库:

my-repo
|-- foo
|   `-- go.mod
|-- go.mod
`-- internal

在这里,只要模块“ my-repo / foo”依赖于模块“ my-repo”,软件包foo就可以导入/ my-repo / internal。同样,在以下存储库中:

my-repo
|-- foo
|   `-- go.mod
`-- internal
    `-- go.mod

在这里,只要模块“ my-repo / foo”依赖于模块“ my-repo / internal”,软件包foo就可以导入my-repo / internal。两者的语义相同:由于my-repo是my-repo / internal和my-repo / foo之间的共享路径前缀,因此允许foo包导入内部包。

额外的go.mod可以排除不必要的内容吗?模块是否等效于.gitignore文件?

go.mod
go.mod
.gogo.mod.go

常见问题解答–最小版本选择

最少的版本选择是否会使开发人员无法获得重要的更新?

请参阅问题“最小版本选择是否会使开发人员无法获得重要更新?” 在较早的FAQ中,来自官方提案的讨论。

常见问题解答-可能的问题

如果我发现问题,可以进行哪些常规检查?

go envGOMODGOMODgo envGO111MODULE=onGO111MODULES=onS-mod=vendorgo build GOFLAGS=-mod=vendorvendorgovendorgo list -m allgo list -m allgo.modgo get foogo buildfoogo get -v foogo get -v -x foogo getgo build-vgo getgo get -v -x foogovgogogo clean -modcache

当前正在检查的错误可能是由于构建中没有特定模块或软件包的预期版本而引起的第二个问题。因此,如果导致特定错误的原因不明显,则可以按照下一个FAQ中的说明对您的版本进行抽查。

如果没有看到期望的依赖版本,该如何检查?

go mod tidygo.mod.gogo mod tidygo.modgo list -mod=readonly allgo list -m allgo list -m allreplaceexcludego mod graphgo mod graph | grep go mod graph
go mod why -m 
go list
go list -deps -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' ./... | sort -u

用于询问你的模块的更详细的命令集和实施例的能够在可运行“转到模块通过实施例”中可以看出walkthough。

go.modv2.0.1module foogo.mod/v2.go/v3requirego.mod/v4go.mod

为什么会出现错误“找不到提供软件包foo的模块”?

这是一条常见的错误消息,可能会因几种不同的根本原因而发生。

在某些情况下,此错误仅是由于路径键入错误引起的,因此第一步可能应该是根据错误消息中列出的详细信息再次检查错误的路径。

go get -v foogo get -v -x foo
go getgo build

其他一些可能的原因:

为什么“ go mod init”给出错误“无法确定源目录的模块路径”?

go mod initgo mod init
go mod initgo mod init github.com/you/hello

我有一个尚未选择模块的复杂依赖性问题。我可以使用其当前依赖项管理器中的信息吗?

是。这需要一些手动步骤,但在某些更复杂的情况下可能会有所帮助。

go mod initGopkg.lockglide.lockvendor.jsongo.modrequireGopkg.lock

但是,如果改为添加尚未选择加入模块本身的新依赖项,则任何先前的依赖项管理器都不会使用类似的自动转换过程,而新的依赖项可能已经在使用该转换过程。如果该新依赖项本身具有发生了重大更改的非模块依赖项,则在某些情况下可能会导致不兼容问题。换句话说,新依赖项的先前依赖项管理器不会自动使用,在某些情况下,这可能会导致间接依赖项出现问题。

go mod initrequirego.modgo.mod
github.com/some/nonmodule
$ git clone -b v1.2.3 https://github.com/some/nonmodule /tmp/scratchpad/nonmodule
$ cd /tmp/scratchpad/nonmodule
$ go mod init
$ cat go.mod
requirego.modgo.modrequire github.com/some/nonmodule v1.2.3go.mod
github.com/sirupsen/logrusgithub.com/Sirupsen/logrus

如何解决由于导入路径与声明的模块标识不匹配而导致的“解析go.mod:意外的模块路径”和“错误加载模块要求”错误?

为什么会发生此错误?

go.modmodulemodule example.com/mgogo.modmodule example.com/mimport "example.com/m"import "example.com/m/sub/pkg"
goparsing go.mod: unexpected module pathgoerror loading module requirements
github.com/Sirupsen/logrusgithub.com/sirupsen/logrusgithub.com/golang/syncgolang.org/x/sync
github.com/Sirupsen/logrusgithub.com/golang/syncgo.mod

问题场景示例

github.com/Quasilyte/go-consistentgithub.com/quasilyte/go-consistentQqgo get -ugithub.com/Quasilyte/go-consistentgo.modmodule github.com/quasilyte/go-consistent

解决

错误的最常见形式是:

example.com/some/NEW/namego.modmastergo.modmodule example.com/some/NEW/name

本节的其余部分重点在于按顺序执行以下步骤来解决此错误的“旧名称”和“新名称”形式:

example.com/some/OLD/nameexample.com/some/NEW/namego get
go get golang.org/dl/gotip && gotip download
gotip get -u all
gotip mod tidy
go mod tidygo.modgithub.com/golang/lintgolang.org/x/lint
replace github.com/Quasilyte/go-consistent => github.com/Quasilyte/go-consistent 00dd7fb039e
replacego.modgo get -ugo mod graph | grep github.com/Quasilyte/go-consistentreplace
export GOPATH=$(mktemp -d)
go get -u foo               # peform operation that generates the error of interest
cd $GOPATH/pkg/mod
grep -R --include="*.go" github.com/Quasilyte/go-consistent
go.modgo.modgo.modgo.modmodule

为什么“开始构建”需要gcc,为什么不使用诸如net / http之类的预构建软件包?

简而言之:

GO111MODULE=on
import "./subdir"

否。请参阅#26645,其中包括:

某些供应商目录中可能没有所需的文件

.govendorgo mod vendor
.go

以cgo为例,修改其他目录中的C源代码不会触发重建,而是您的构建将使用陈旧的缓存条目。cgo文档现在包括:

vendor.go

请参阅#26366中的其他讨论。

传统供应商的另一种方法是检入模块缓存。它最终可能会获得与传统供应商类似的好处,并且在某些方面最终会获得更高的保真度。将此方法解释为“通过示例执行模块” 演练。