官方原文: https://github.com/golang/go/wiki/Modulesgit
Go 1.11包括此处建议的对版本模块的初步支持。模块是Go 1.11中的实验性加入功能,并计划归入反馈并最终肯定 Go 1.14中的功能。即便某些细节可能会更改,未来的发行版也将支持使用Go 1.十一、1.12和1.13定义的模块。github
最初的原型vgo
于2018年2月宣布。2018年7月,版本化的模块进入了主Go存储库。golang
Go 1.13中对模块进行了重大改进和更改。shell
若是使用模块,请务必仔细阅读Go 1.13发行说明的模块部分。数据库
三个值得注意的变化:json
该go
工具如今默认为从https://proxy.golang.org上的公共Go模块镜像下载模块,而且还默认为针对https://sum.golang.org上的公共Go校验和数据库验证下载的模块(不管源如何)。vim
GOPRIVATE
设置(例如go env -w GOPRIVATE=*.corp.com,github.com/secret/repo
),或者配置更细粒度的变体,GONOPROXY
或者GONOSUMDB
支持使用频率较低的用例。有关更多详细信息,请参见文档。GO111MODULE=auto
若是找到任何go.mod,即便在GOPATH内部,也将启用模块模式。(在Go 1.13以前,GO111MODULE=auto
永远不会在GOPATH中启用模块模式)。api
go get
参数已更改:缓存
go get -u
(不带任何参数)如今仅升级当前软件包的直接和间接依赖关系,而再也不检查整个模块。go get -u ./...
从模块根目录升级模块的全部直接和间接依赖关系,如今不包括测试依赖关系。go get -u -t ./...
类似,但也升级了测试依赖项。go get
再也不受支持-m
(由于go get -d
因为其余更改,它会在很大程度上与重叠;您一般能够替换go get -m foo
为go 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.mod
文件已更新为包括依赖项的显式版本,v1.5.2
这里是语义化版本号标签:
$ cat go.mod module github.com/my/repo require rsc.io/quote v1.5.2
请注意,go get
上面的示例中没有要求。
典型的平常工做流程能够是:
.go
根据须要将导入语句添加到您的代码中。go build
或)go test
会根据须要自动添加新的依赖关系,以实现导入(更新go.mod
和下载新的依赖关系)。go get foo@v1.2.3
,go get foo@master
(foo@tip
带有Mercurial)go get foo@e3702bed2
,或go.mod
直接编辑等命令来选择更具体的依赖关系版本。您可能会使用的其余常见功能的简要介绍:
go list -m all
—查看将在构建中用于全部直接和间接依赖关系的最终版本(详细信息)go list -u -m all
—查看全部直接和间接依赖项的可用次要和补丁升级(详细信息)go get -u ./...
或go get -u=patch ./...
(从模块根目录)—将全部直接和间接依赖关系更新为最新的次要或补丁升级(忽略预发行版)(详细信息)go build ./...
或go test ./...
(从模块根目录)—构建或测试模块中的全部软件包(详细信息)go mod tidy
从go.mod
OS,架构和构建标签的其余组合中修剪全部不须要的依赖项,并添加其余依赖项所需的任何依赖项(详细信息)replace
指令或gohack
—使用派生,本地副本或依赖项的确切版本(详细信息)go mod vendor
—建立vendor
目录的可选步骤(详细信息)在阅读了有关“新概念”的下四个部分以后,您将得到足够的信息来开始使用大多数项目的模块。查看上面的目录(包括此处的FAQ常见问题解答)以使本身熟悉更详细的主题列表也颇有用。
这些部分对主要的新概念进行了高级介绍。有关更多详细信息和原理,请观看Russ Cox的这段40分钟的介绍性视频,其中介绍了设计背后的理念,正式的建议文档或更为详细的初始vgo博客系列。
一个模块是一些以版本做为单元相关的包的集合。
模块记录精确的依赖要求并建立可复制的构建。
一般,版本控制存储库仅包含在存储库根目录中定义的一个模块。(单个存储库中支持多个模块,可是一般,与每一个存储库中的单个模块相比,这将致使正在进行的工做更多)。
总结存储库,模块和软件包之间的关系:
模块必须根据在语义版本语义化版本号,一般在形式v(major).(minor).(patch)
,如 v0.1.0
,v1.2.3
,或v1.5.0-rc.1
。领导v
是必需的。若是使用Git,则标记发布会提交其版本。公共和私有模块存储库和代理均可以使用(请参阅下面的常见问题解答)。
模块由Go源文件树定义,该go.mod
文件在树的根目录中。模块源代码可能位于GOPATH以外。有四种指令:module
,require
,replace
,exclude
。
这是go.mod
定义模块的示例文件github.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.mod
经过module
提供模块path的指令在其声明中声明其身份。模块中全部软件包的导入路径将模块路径共享为公共前缀。模块路径和从go.mod
到软件包目录的相对路径共同肯定了软件包的导入路径。
例如,若是要为存储库建立一个模块,该模块github.com/my/repo
将包含两个带有导入路径github.com/my/repo/foo
和的软件包github.com/my/repo/bar
,则go.mod
文件中的第一行一般会将模块路径声明为module github.com/my/repo
,相应的磁盘结构能够是:
repo |-- bar | `-- bar.go |-- foo | `-- foo.go `-- go.mod
在Go源代码中,将使用完整路径(包括模块路径)导入软件包。例如,若是一个模块在go.mod
as中声明其身份module example.com/my/module
,则使用者能够执行如下操做:
import "example.com/my/module/mypkg"
这mypkg
将从模块导入包example.com/my/module
。
exclude
而replace
指令仅在当前(“主”)模块上运行。在构建主模块时,将忽略除主模块之外的其余模块中的指令exclude
和replace
指令。该replace
和exclude
语句,所以,容许在本身的构建主要模块的彻底控制权,也没有受制于由依赖于彻底控制。(有关什么时候使用指令的讨论,请参见下面的常见问题解答replace
)。
若是您在源代码中添加了一个还没有被require
in 覆盖的新导入,则go.mod
大多数go命令(例如“ go build”和“ go test”)将自动查找适当的模块,并将该新直接依赖项的最高版本添加到您的模块go.mod
是require
指令。例如,若是您的新导入对应于依赖项M,其最新标记版本为v1.2.3
,则模块的go.mod
结尾将为require M v1.2.3
,这表示模块M是容许版本> = v1.2.3(且<v2,由于v2被认为不兼容)的依赖项与v1)。
在最小的版本选择算法用来选择在构建中使用的全部模块的版本。对于构建中的每一个模块,经过最小版本选择选择的版本始终是主模块中的指令或其依赖项之一明确列出的版本的语义上最高的版本require
。
例如,若是您的模块依赖于具备A的模块A require D v1.0.0
,而您的模块也依赖于具备A的模块B require D v1.1.1
,则最小的版本选择将选择v1.1.1
D包含在构建中(假设它是列出的最高require
版本)。v1.1.1
即便稍后某个v1.2.0
D可用,对D的选择仍保持一致。这是模块系统如何提供100%可复制构建的示例。准备就绪后,模块做者或用户能够选择升级到D的最新可用版本,或为D选择一个显式版本。
有关最小版本选择算法的简要原理和概述,请参阅官方建议书的“高保真度构建”部分,或查看更详细的vgo
博客系列。
要查看所选模块版本的列表(包括间接依赖关系),请使用go list -m all
。
另请参见下面的“如何升级和降级依赖项”部分和“如何将版本标记为不兼容?” 下面的常见问题解答。
多年以来,官方的Go常见问题解答已在软件包版本管理中包括如下建议:
“面向公共用途的软件包应在发展过程当中尝试保持向后兼容性。Go1兼容性指南在此处是很好的参考:请勿删除导出的名称,鼓励带标签的复合文字等等。若是须要不一样的功能,请添加一个新名称,而不是更改旧名称。若是须要彻底中断,请建立一个具备新导入路径的新软件包。”
最后一句特别重要-若是破坏兼容性,则应更改软件包的导入路径。使用Go 1.11模块,该建议被正式化为导入兼容性规则:
“若是旧软件包和新软件包具备相同的导入路径,则新软件包必须与旧软件包向后兼容。”
当v1或更高版本的软件包进行向后不兼容的更改时,召回语义化版本号须要对主要版本进行更改。遵循导入兼容性规则和语义化版本号的结果称为语义导入版本控制,其中主要版本包含在导入路径中-这可确保在主要版本因为兼容性中断而增长时,导入路径都会更改。
因为语义导入版本控制,选择加入Go模块的代码必须遵照如下规则:
v1.2.3
)。/vN
在go.mod
文件(例如module github.com/my/mod/v2
,require github.com/my/mod/v2 v2.0.1
)和包导入路径(例如import "github.com/my/mod/v2/mypkg"
)中使用的模块路径的末尾将主要版本做为包括在内。这包括go get
命令中使用的路径(例如,go get github.com/my/mod/v2@v2.0.1
请注意,在该示例中同时包含a /v2
和a @v2.0.1
。一种考虑方式是模块名称如今包括/v2
,所以/v2
不管什么时候使用模块名称,都包括)。一般,具备不一样导入路径的软件包是不一样的软件包。例如,与math/rand
是不一样的软件包crypto/rand
。若是不一样的导入路径是因为导入路径中出现的主要版本不一样而致使的,则也是如此。所以,与example.com/my/mod/mypkg
包是一个不一样的包example.com/my/mod/v2/mypkg
,二者均可以在一个单一版本中导入,这除其余优势外还有助于解决钻石依赖问题,而且还容许在替换v2方面实施v1模块,反之亦然。
有关语义导入版本控制的更多详细信息,请参见命令文档的“模块兼容性和语义版本控制”部分,go
有关语义版本控制的更多信息,请参见https://语义化版本号.org。
到目前为止,本节的重点是已选择加入模块并导入其余模块的代码。可是,将主要版本置于v2 +模块的导入路径中可能会与Go的较早版本或还没有选择加入模块的代码产生不兼容性。为了解决这个问题,上述行为和规则有三种重要的过渡性特殊状况或例外。随着愈来愈多的程序包加入模块,这些过渡性异常将再也不重要。
三个例外:
gopkg.in
使用导入路径gopkg.in
(以gopkg.in/yaml.v1
和开头)的现有代码gopkg.in/yaml.v2
即便选择加入模块,也能够继续将这些格式用于其模块路径和导入路径。
导入非模块v2 +软件包时为“ +不兼容”
模块能够导入还没有选择加入模块的v2 +软件包。具备有效v2 + 语义化版本号标签的非模块v2 +软件包将+incompatible
在导入模块的go.mod
文件中记录后缀。该+incompatible
后缀表示,即便V2 +包有一个有效的V2 + 语义化版本号标签,例如v2.0.0
,使V2 +包没有主动选择的模块和假设,所以该V2 +包都没有被与语义进口版本的含义的理解产生以及如何在导入路径中使用主要版本。所以,当以模块模式运行时,go
该工具会将非模块v2 +软件包视为该软件包的v1版本系列的(不兼容)扩展,并假定该软件包不了解语义导入版本控制,而且+incompatible
后缀表示该go
工具正在这样作。
未启用模块模式时的“最小模块兼容性”
为了帮助向后兼容,对Go版本1.9.7 +,1.10.3 +和1.11进行了更新,以使使用这些发行版构建的代码可以更轻松地正确使用v2 +模块,而无需修改现有代码。此行为称为“最小模块兼容性”,而且仅在禁用该工具的完整模块模式时才生效go
,例如您GO111MODULE=off
在Go 1.11中进行了设置,或者正在使用Go 1.9.7+或1.10.3版本+。当依靠Go 1.9.7 +,1.10.3 +和1.11中的这种“最小模块兼容性”机制时,未选择模块的软件包将不会在任何导入的v2 +模块的导入路径中包含主版本。相比之下,已选择在模块必须包括在导入路径主要版本导入任何V2 +模块(为了正确导入V2 +模块时的go
工具在全模块模式语义进口版本的充分认识工做)。
有关发布v2 +模块所需的确切机制,请参阅下面的“发布模块(v2或更高版本)”部分。
要使用模块,两个安装选项是:
master
分支上的源代码安装Go工具链。安装后,您能够经过如下两种方式之一激活模块支持:
go
在$GOPATH/src
树以外的目录中调用命令,并go.mod
在当前目录或其任何父目录中使用有效文件,而且未GO111MODULE
设置(或显式设置为auto
)环境变量。go
带有GO111MODULE=on
环境变量设置的命令。为go.mod
现有项目建立一个:
导航到GOPATH以外的模块源代码树的根目录:
$ cd <project path outside $GOPATH/src> # e.g., cd ~/projects/hello
请注意,在GOPATH以外,您无需进行设置GO111MODULE
便可激活模块模式。
或者,若是要在GOPATH中工做:
$ export GO111MODULE=on # manually active module mode $ cd $GOPATH/src/<project path> # e.g., cd $GOPATH/src/you/hello
建立初始模块定义并将其写入go.mod
文件:
$ go mod init
此步骤从任何现有文件或其余全部9种受支持的依赖项格式中的任何一种转换,添加require语句以匹配现有配置。dep
Gopkg.lock
go mod init
一般可使用辅助数据(例如VCS元数据)来自动肯定适当的模块路径,可是若是go mod init
状态不能自动肯定模块路径,或者若是您须要以其余方式覆盖该路径,则能够提供模块路径做为的可选参数go mod init
,例如:
$ go mod init github.com/my/repo
请注意,若是您的依赖项包括v2 +模块,或者正在初始化v2 +模块,则在运行后,go mod init
您可能还须要编辑go.mod
和.go
代码,以添加/vN
导入路径和模块路径,如上面“语义导入版本控制”部分所述。即便go mod init
自动从dep
或其余依赖项管理器转换了您的依赖项信息,这也适用。(所以,在运行以后go mod init
,一般go mod tidy
只有在成功运行go build ./...
或相似操做后才能运行,这是本节中显示的顺序)。
生成模块。从模块的根目录执行时,该./...
模式将匹配当前模块中的全部软件包。 go build
会根据须要自动添加缺乏或未转换的依赖项,以知足此特定构建调用的导入需求:
$ go build ./...
按照配置测试模块,以确保它能够与所选版本一块儿使用:
$ go test ./...
(可选)运行模块的测试以及全部直接和间接依赖项的测试,以检查不兼容性:
$ go test all
在标记发行版以前,请参见下面的“如何准备发行版”部分。
有关全部这些主题的更多信息,可在golang.org上找到官方模块文档的主要入口点。
平常的依赖关系升级和降级应该使用“ go get”完成,它将自动更新go.mod
文件。或者,您能够go.mod
直接编辑。
此外,执行“执行构建”,“执行测试”甚至“执行列表”之类的go命令将根据须要自动添加新的依赖关系,以知足导入要求(更新go.mod
和下载新的依赖关系)。
要查看全部直接和间接依赖项的可用次要和补丁升级,请运行go list -u -m all
。
要将当前模块的全部直接和间接依赖关系升级到最新版本,能够在模块根目录中运行如下命令:
go get -u ./...
使用最新的次要版本或补丁程序版本(并添加-t
以升级测试依赖项)go get -u=patch ./...
使用最新的补丁程序发行版(并添加-t
以升级测试依赖项)go get foo
更新到的最新版本foo
。go get foo
等效于go get foo@latest
—换句话说,@latest
若是未@
指定版本,则为默认值。
在本节中,“最新”是带有语义化版本号标签的最新版本,或者若是没有语义化版本号标签则是最新的已知提交。除非存储库中没有其余语义化版本号标签,不然不会将预发布标签选择为“最新”标签(details)。
一个广泛的错误是认为go get -u foo
仅获取最新版本的foo
。实际上,-u
in go get -u foo
或的go get -u foo@latest
意思是还得到的全部直接和间接依赖关系的最新版本foo
。升级时,一个共同的起点foo
是否是作go get foo
或go get foo@latest
没有-u
(和后一切正常,能够考虑go get -u=patch foo
,go get -u=patch
,go get -u foo
,或go get -u
)。
要升级或降级到一个更具体的版本,“去把”容许版本选择经过添加一个后缀@version或覆盖“模块查询”到包的说法,好比go get foo@v1.6.2
,go get foo@e3702bed2
或者go get foo@'<v1.6.2'
。
不管是否具备语义化版本号标记,使用分支名称(例如go get foo@master
(foo@tip
带有mercurial))都是获取最新提交的一种方法。
一般,不能解析为语义化版本号标签的模块查询将做为伪版本记录在go.mod
文件中。
有关此处的主题的更多信息,请参见命令文档的“支持模块的获取”和“模块查询”部分go
。
模块可以使用还没有加入模块的软件包,包括在其中记录任何可用的语义化版本号标签go.mod
并使用这些语义化版本号标签进行升级或降级。模块还可使用尚没有任何适当语义化版本号标签的软件包(在这种状况下,它们将使用中的伪版本进行记录go.mod
)。
在升级或降级任何依赖项以后,您可能想要对构建中的全部软件包(包括直接和间接依赖项)再次运行测试以检查不兼容性:
$ go test all
建立模块发行版的最佳实践有望做为初始模块实验的一部分出现。其中许多最终可能会由未来的“发布”工具自动化。
在标记版本以前,应考虑一些当前建议的最佳作法:
运行go mod tidy
到可能修剪任何无关的要求(如描述在这里),并确保您的当前go.mod反映了全部可能的堆积标签/ OS /架构的组合(如描述在这里)。
go build
而且go test
不会从中删除依赖项)go.mod
再也不须要,而是仅go.mod
基于当前构建调用的标记/ OS /体系结构进行更新。运行go test all
以测试您的模块(包括针对直接和间接依赖项运行测试),以验证当前所选软件包版本是否兼容。
go test all
已被从新定义为更有用:经过一个或多个导入序列,将当前模块中的全部软件包以及它们所依赖的全部软件包包括在内,而在其中将可有可无的软件包排除在外当前模块。若是要发布v2或更高版本的模块,请首先查看上面“语义导入版本控制”部分中的讨论,其中包括为什么在v2 +模块的模块路径和导入路径中包含主要版本以及Go版本1.9的方式.7+和1.10.3+已更新,以简化该过渡。
请注意,若是您是第一次v2.0.0
采用模块,是为了在采用模块以前针对已存在标签或更高版本的预先存在的存储库或软件包集进行采用,那么建议的最佳实践是在首次采用模块时增长主版本。例如,若是您是的做者foo
,而且foo
存储库的最新标记是v2.2.2
,而且foo
还没有采用模块,则最佳作法是v3.0.0
将第一个版本的foo
采用采用模块(所以将第一个版本的foo
to做为)。包含一个go.mod
文件)。在这种状况下,增长主要版本可为的使用者提供更大的清晰度foo
,从而容许在v2系列的其余非模块补丁或次要发行版上使用foo
若是须要,并提供了一个基于模块的消费者一个强烈的信号foo
,不一样的主要版本,若是你作的结果import "foo"
和相应的require foo v2.2.2+incompatible
,与import "foo/v3"
和相应require foo/v3 v3.0.0
。(请注意,关于递增主要版本时,首先采用模块不会这个建议并不适用于预先存在的回购或包,其最新版本v0.xx或v1.xx)。
有两种替代机制能够发布v2或更高版本的模块。请注意,使用这两种技术,当模块做者推送新标签时,新模块版本就能够供消费者使用。以建立v3.0.0
发行版为例,两个选项是:
Major分支:更新go.mod
文件以/v3
在module
指令的模块路径末尾包含a (例如module github.com/my/module/v3
)。更新模块中的import语句以也使用/v3
(例如import "github.com/my/module/v3/mypkg"
)。用标记发布v3.0.0
。
v3.*.*
模块的提交放在单独的v3分支上。v3.0.0
在master上进行标记,那么这是一个可行的选择。(可是,要知道,在引入一个不兼容的API的变化master
可能会致使谁发出非模块用户的问题go get -u
给出的go
工具是不知道的语义化版本号以前去1.11或当模块模式在Go 1.11+未启用)。dep
当前之类的现有依赖关系管理解决方案在使用这种方式建立的v2 +模块时可能会遇到问题。参见例如dep#1962。主要子目录:建立一个新的v3
子目录(例如my/module/v3
),而后go.mod
在该子目录中放置一个新文件。模块路径必须以结尾/v3
。将代码复制或移动到v3
子目录中。更新模块中的import语句以也使用/v3
(例如import "github.com/my/module/v3/mypkg"
)。用标记发布v3.0.0
。
goforward
。请在此处查看更多详细信息和基本原理,以及可正常运行的goforward
。dep
应该可以使用以这种方式建立的v2 +模块。有关这些替代方案的更深刻讨论,请参见https://research.swtch.com/vgo-module。
能够经过将标签推送到包含模块源代码的资源库中来发布新的模块版本。标签是经过串联两个字符串造成的:前缀和版本。
该版本是该发行版的语义导入版本。应该按照语义导入版本控制规则进行选择。
所述前缀指示其中模块的存储库中定义的。若是模块是在存储库的根目录中定义的,则前缀为空,而标记仅为版本。可是,在多模块存储库中,前缀区分不一样模块的版本。前缀是存储库中定义模块的目录。若是存储库遵循上述主要子目录模式,则前缀不包括主要版本后缀。
例如,假设咱们有一个模块example.com/repo/sub/v2
,而且咱们要发布version v2.1.6
。存储库根目录与相对应example.com/repo
,而且模块sub/v2/go.mod
在存储库内定义。此模块的前缀是sub/
。此版本的完整标签应为sub/v2.1.6
。
本节试图简要列举迁移到模块时要作出的主要决定,并列出其余与迁移相关的主题。一般会提供其余部分的参考,以获取更多详细信息。
该材料主要基于模块实验中社区中出现的最佳实践。所以,这是一个进行中的部分,随着社区得到更多的经验,该部分将有所改善。
摘要:
迁移主题:
go mod init
将所需的信息从dep,glid,govendor,godep和其余5个先前存在的依赖项管理器自动转换为go.mod
生成等效构建的文件。module
转换后的指令中go.mod
包含相应的指令/vN
(例如module foo/v3
)。/vN
到从先前的依赖项管理器转换后生成的require
语句中go mod init
。有关更多详细信息,请参见上面的“如何定义模块”部分。go mod init
将不会编辑您的.go
代码以添加任何须要/vN
导入的语句。有关所需步骤,请参见上面的“语义导入版本控制”和“发布模块(v2或更高版本)”部分,包括围绕社区工具进行自动转换的一些选项。go mod vendor
禁用模块模式时,Go的较早版本了解如何使用由建立的vendor目录,Go 1.11和1.12+也是如此。所以,供应是模块提供依赖的一种方式,该依赖提供了对不能彻底理解模块的Go的较旧版本以及未启用模块自己的使用者的依赖。有关更多详细信息,请参见vendor常见问题解答和go
命令文档。go get -u foo
。若是要发布模块foo
,请考虑-u
为基于模块的使用者使用in指令。
-u
要求go
工具升级的全部直接和间接依赖foo
。go get -u foo
稍后运行,可是若是它不是初始安装说明的一部分,则“ High Fidelity Builds”还有更多好处-u
。有关更多详细信息,请参见“如何升级和降级依赖项”。go get -u foo
仍然有效,而且仍然能够做为安装说明的有效选择。go get foo
对于基于模块的使用者,并不是严格须要。
import "foo"
就足够了。(后续命令如go build
或go test
会根据须要自动下载foo
和更新go.mod
)。vendor
默认状况下,基于模块的使用者将不使用目录。
go
工具中启用了模块模式,vendor
则使用模块时并不须要严格要求(鉴于中包含的信息go.mod
和中的密码校验和go.sum
),可是某些预先存在的安装说明假定该go
工具将vendor
默认使用。有关更多详细信息,请参见vendor常见问题解答。go get foo/...
在某些状况下,安装说明可能包含问题(请参阅#27215中的讨论)。模块go.mod
经过module
指令(例如)在其声明中声明其身份module github.com/my/module
。任何模块支持的使用者都必须使用与模块声明的模块路径匹配的导入路径(确切地说是针对根软件包,或将模块路径做为导入路径的前缀)导入模块内的全部软件包。若是导入路径与相应模块的声明模块路径不匹配,则该go
命令将报告unexpected module path
错误。
在为一组预先存在的软件包采用模块时,应注意避免破坏现有使用者使用的现有导入路径,除非在采用模块时增长主版本。
例如,若是您先前存在的README一直在告诉消费者要使用import "gopkg.in/foo.v1"
,而且随后采用v1版本的模块,则您的首字母go.mod
几乎确定会读为module gopkg.in/foo.v1
。若是您不想使用gopkg.in
,这对您当前的消费者来讲将是一个巨大的变化。一种方法是将其更改成相似的内容(module github.com/repo/foo/v2
若是您稍后转到v2)。
请注意,模块路径和导入路径区分大小写。从更改模块github.com/Sirupsen/logrus
到github.com/sirupsen/logrus
,例如,对消费者来讲是一个重大更改,即便GitHub的自动转发从一个存储库名称到新存储库的名称。
采用模块后,更改模块路径go.mod
是一项重大更改。
整体而言,这相似于经过“导入路径注释”对规范的导入路径进行模块前的强制,有时也称为“导入实用程序”或“导入路径强制”。举例来讲,该软件包go.uber.org/zap
当前托管在github.com/uber-go/zap
,但在软件包声明旁边使用了导入路径注释,该注释为使用错误的基于github的导入路径的全部前置模块使用者触发了错误:
package zap // import "go.uber.org/zap"
go.mod文件的module语句已淘汰了导入路径注释。
v2.0.1
而且还没有采用模块,那么您将使用v3.0.0
采用模块的第一个发行版。有关更多详细信息,请参见上面的“发布模块(v2或更高版本)”部分。foo
而且foo/v3
可能最终在单个版本中)。
foo
和的软件包级别状态foo/v3
),而且每一个主要版本都将运行其本身的init
功能。go.mod
。模块可使用尚没有适当的语义化版本号标签的软件包。有关更多详细信息,请参见下面的常见问题解答。+incompatible
若是导入的v2 +程序包具备有效的语义化版本号标签,它将带有后缀记录。有关更多详细信息,请参见下面的常见问题解答。非模块代码消耗v0和v1模块:
非模块代码消耗v2 +模块:
Go版本1.9.7 +,1.10.3 +和1.11已更新,所以使用这些发行版构建的代码能够正确使用v2 +模块,而无需按“语义导入版本控制”和“发布模块( v2或更高版本)”部分。
若是按照“发布模块(v2或更高版本)”一节中概述的“主要子目录”方法建立v2 +模块,则1.9.7和1.10.3以前的Go版本可使用v2 +模块。
对于考虑加入模块的预先存在的v2 +软件包的做者,总结替代方法的一种方法是在三种顶级策略之间进行选择。每一个选择都有后续的决定和变化(如上所述)。这些替代的顶级策略是:
要求客户端使用Go版本1.9.7 +,1.10.3 +或1.11+。
该方法使用“主要分支”方法,并依赖于“最小模块感知”,该模型被反向移植到1.9.7和1.10.3。有关更多详细信息,请参见上面的“语义导入版本控制”和“发布模块(v2或更高版本)”部分。
容许客户使用甚至更旧的Go版本,如Go 1.8。
此方法使用“主要子目录”方法,并涉及建立子目录,例如/v2
或/v3
。有关更多详细信息,请参见上面的“语义导入版本控制”和“发布模块(v2或更高版本)”部分。
等待加入模块。
在这种策略下,事情继续与选择了模块的客户端代码以及未选择模块的客户端代码一块儿工做。随着时间的流逝,Go版本1.9.7 +,1.10.3 +和1.11+的发布时间将愈来愈长,而且在未来的某个时候,要求Go版本变得更加天然或对客户友好1.9.7 + / 1.10.3 + / 1.11 +,此时,您能够实施以上策略1(须要Go版本1.9.7 +,1.10.3 +或1.11+),甚至能够实施以上策略2(可是若是最终要采用上述策略2来支持1.8等旧版Go,那么您如今就能够这样作。
该require
指令容许任何模块声明其应使用依赖项D的版本> = xyz构建(因为与模块D的版本<xyz不兼容而可能指定)。经验数据代表,这是在dep
和中使用的约束的主要形式cargo
。此外,构建中的顶层模块能够使用不一样的代码来生成exclude
特定版本的依赖项或replace
其余模块。有关更多详细信息和原理,请参阅完整建议。
版本模块建议的主要目标之一是为工具和开发人员在Go代码的版本周围添加通用词汇和语义。这为未来声明不兼容的其余形式奠基了基础,例如:
vgo
博客系列一般,模块是Go 1.11的可选组件,所以,根据设计,默认状况下会保留旧的行为。
总结什么时候得到旧的1.10现状行为与新的基于选择加入模块的行为:
go.mod
- 的文件树中-默认为模块行为auto
-上面的默认行为on
—无论目录位置如何,都强制支持模块off
—无论目录位置如何,都强制关闭模块支持go get
错误安装工具会失败并显示错误cannot find main module
?当您进行设置GO111MODULE=on
但go.mod
运行时不在文件树内部时,会发生这种状况go get
。
最简单的解决方案是保持未GO111MODULE
设置状态(或等效地显式设置为GO111MODULE=auto
),这样能够避免出现此错误。
回想一下存在的主要缘由之一是记录精确的依赖项信息。此依赖项信息将写入您的current go.mod
。若是您不在带有的文件树中,go.mod
可是go get
经过设置告诉命令以模块模式GO111MODULE=on
运行,则运行go get
将致使错误,cannot find main module
由于没有go.mod
可用来记录依赖项信息的信息。
解决方案的替代方案包括:
保持未GO111MODULE
设置状态(默认设置或显式设置GO111MODULE=auto
),这将致使更友好的行为。当您不在模块中时,这将为您提供Go 1.10行为,从而避免了go get
报告cannot find main module
。
export GO111MODULE=on
,但根据须要暂时禁用模块,并在过程当中启用Go 1.10行为go get
,例如via GO111MODULE=off go get example.com/cmd
。能够将其转换为简单的脚本或shell别名,例如alias oldget='GO111MODULE=off go get'
建立一个临时go.mod
文件,而后将其丢弃。这已经经过@rogpeppe的简单shell脚本实现了自动化。该脚本容许经过可选地提供版本信息vgoget example.com/cmd[@version]
。(这是避免错误的解决方案cannot use path@version syntax in GOPATH mode
)。
gobin
是可识别模块的命令,用于安装和运行主软件包。默认状况下,gobin
无需先手动建立模块便可安装/运行主程序包,但-m
能够经过标志将该命令告知使用现有模块来解决依赖关系。请参阅gobin
自述文件和常见问题解答以了解详细信息和其余用例。
建立一个go.mod
用于跟踪运行的全局安装工具(例如中的)~/global-tools/go.mod
,而后cd
在运行以前跟踪该目录,go get
或跟踪go install
全部全局安装的工具。
go.mod
为每一个工具在单独的目录(例如~/tools/gorename/go.mod
和)中建立一个~/tools/goimports/go.mod
,并cd
在运行前为该工具go get
或go install
该工具建立一个相应的目录。
该当前限制将获得解决。可是,主要问题是模块当前处于启用状态,完整的解决方案可能要等到GO111MODULE = on成为默认行为。有关更多讨论,请参见#24250,包括此评论:
显然,这最终必须起做用。就该版本而言,我不肯定这究竟是作什么的:它会建立一个临时模块root和go.mod,执行安装,而后将其丢弃吗?大概。可是我不太肯定,就目前而言,我不想让vgo在go.mod树以外作一些事情来令人们感到困惑。固然,最终的go命令集成必须支持这一点。
该常见问题解答一直在讨论跟踪全局安装的工具。
相反,若是要跟踪特定模块所需的工具,请参阅下一个FAQ。
若是你:
stringer
在处理模块时使用基于Go的工具(例如),而且go.mod
文件中跟踪该工具的版本那么当前推荐的一种方法是将一个tools.go
文件添加到您的模块中,该文件包括目标工具(例如import _ "golang.org/x/tools/cmd/stringer"
)的导入语句以及// +build tools
构建约束。import语句使go
命令能够在模块的中精确记录工具的版本信息go.mod
,而// +build tools
构建约束阻止正常的构建实际导入工具。
有关如何执行此操做的具体示例,请参见本“经过示例执行模块”演练。
简要理由(一样来自#25922):
我认为tools.go文件其实是工具依赖关系的最佳实践,固然对于Go 1.11。
我喜欢它,由于它没有引入新的机制。
它只是简单地重用现有的。
对模块的支持已开始在编辑器和IDE中得到。
例如:
go.mod
已经到来。#1906年得到了更普遍的支持。在雨伞问题中一直跟踪其余工具(例如goimports,guru,gorename和相似工具)的状态#24661。请查看该伞的最新状态。
特定工具的一些跟踪问题包括:
nsf/gocode
建议人们从迁移nsf/gocode
到mdempsky/gocode
。一般,即便您的编辑器,IDE或其余工具还没有被模块识别,若是您在GOPATH内使用模块而且可使用,则它们的大部分功能也应与模块一块儿使用go mod vendor
(由于应经过GOPATH来选择适当的依赖项) 。
完整的解决方法是把那包加载关闭的程序go/build
和到golang.org/x/tools/go/packages
,其知道如何定位模块感知方式封装。这极可能最终成为事实go/packages
。
社区开始在模块之上构建工具。例如:
replace
和多模块工做流程,其中包括容许您轻松修改其中的一个依赖项gohack example.com/some/dependency
自动克隆适当的存储库并将必要的replace
指令添加到您的go.mod
gohack undo
go.mod
在go源代码中自动调整文件和相关的导入语句mgit -tag +0.0.1
)vendor/
文件夹中,例如外壳程序脚本,.cpp文件,.proto文件等。如上面“ go.mod”概念部分所述,replace
伪指令在顶层提供了额外的控制权,go.mod
用于实际知足Go源代码或go.mod文件中找到的依赖关系,而replace
伪指令则位于主模块以外的模块中构建主模块时,将忽略该模块。
该replace
指令容许您提供另外一个导入路径,该路径多是VCS(GitHub或其余地方)中的另外一个模块,或者是具备相对或绝对文件路径的本地文件系统上的另外一个模块。replace
使用指令中的新导入路径,而无需更新实际源代码中的导入路径。
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
也可用于将多模块项目中模块的相对或绝对磁盘上位置通知go工具,例如:
replace example.com/project/foo => ../foo
注意:若是replace
指令的右侧是文件系统路径,则目标必须go.mod
在该位置具备文件。若是该go.mod
文件不存在,则可使用建立一个go mod init
。
一般,您能够选择=>
在replace指令的左侧指定版本,可是一般,若是您忽略此更改,则对更改的敏感性较低(例如,如replace
上述全部示例所示)。
在Go 1.11中,对于直接依赖关系require
,即便执行时也须要一个指令replace
。例如,若是foo
是直接依赖项,那么您不能没有replace foo => ../foo
相应的require
for foo
。若是你不知道在用什么版本的require
指令,你能够常用v0.0.0
如require foo v0.0.0
。这在Go 1.12中的#26241中获得了解决。
您能够经过运行确认得到所需的版本go list -m all
,该版本向您显示了将在构建中使用的实际最终版本,包括考虑了replace
语句。
有关更多详细信息,请参见“ go mod edit”文档。
github.com/rogpeppe/gohack使这些类型的工做流变得更加容易,尤为是若是您的目标是对模块依赖项进行可变签出时。有关概述,请参见存储库或以前的常见问题解答。
有关在replace
VCS以外彻底使用的详细信息,请参见下一个FAQ 。
是。不须要VCS。
若是您要一次在VCS以外编辑单个模块,那么这很是简单(而且您总共只有一个模块,或者其余模块位于VCS中)。在这种状况下,能够将包含单个文件的文件树放置go.mod
在方便的位置。你go build
,go test
和相似的命令将工做,即便你的单个模块是VCS以外(无需任何使用replace
你的go.mod
)。
若是要在本地磁盘上同时编辑多个相互关联的模块,则replace
指令是一种方法。如下是一个示例go.mod
,该示例使用replace
带有相对路径的将hello
模块指向该模块在磁盘上的位置goodbye
(不依赖任何VCS):
module example.com/me/hello require ( example.com/me/goodbye v0.0.0 ) replace example.com/me/goodbye => ../goodbye
如本示例所示,若是在VCS以外,则能够将其v0.0.0
用做require
指令中的版本。请注意,如先前的FAQ中所述,在Go 1.11中require
必须在此处手动添加require
指令,但再也不须要在Go 1.12+(#26241)中手动添加该指令。
该线程中显示了一个小的可运行示例。
最初的一系列vgo
博客文章确实建议彻底放弃vendor,可是社区的反馈致使保留了对vendor的支持。
简而言之,要对模块使用vendor:
go mod vendor
重置主模块的vendor目录,以包括根据go.mod文件和Go源代码的状态构建和测试全部模块软件包所需的全部软件包。go build
在模块模式下,执行诸如忽略vendor目录之类的命令。-mod=vendor
标志(例如,go build -mod=vendor
)指示去命令使用主模块的顶级vendor目录,以知足依赖性。所以,在此模式下,go命令将忽略go.mod中的依赖项描述,并假定vendor目录包含正确的依赖项副本。请注意,仅使用主模块的顶级vendor目录。其余位置的vendor目录仍然被忽略。GOFLAGS=-mod=vendor
环境变量来按期选择vendor。禁用模块模式go mod vendor
时,Go的较旧版本(如1.10)了解如何使用由建立的vendor目录,Go 1.11和1.12+ 也是如此。所以,供应是模块提供依赖的一种方式,该依赖提供了对不能彻底理解模块的Go的较旧版本以及未启用模块自己的使用者的依赖。
若是您正在考虑使用vendor,则值得阅读技巧文档中的“模块和vendor”和“提供依赖关系的vendor副本”部分。
公共托管的“始终在”不可变模块存储库以及可选的私有托管的代理和存储库正变得可用。
例如:
请注意,您不须要运行代理。相反,1.11中的go工具已经过GOPROXY添加了可选的代理支持,以启用更多企业用例(例如,更好的控制),并更好地处理诸如“ GitHub停机”或人们删除GitHub存储库的状况。
默认状况下,相似的命令go build
会根据须要到达网络以达到导入要求。
有些团队可能但愿禁止go工具在某些时候接触网络,或者想要更好地控制go工具什么时候更新go.mod
,如何得到依赖关系以及如何使用vendor。
转到工具提供了至关数量的灵活调整或关闭这些默认的行为,包括经过-mod=readonly
,-mod=vendor
,GOFLAGS
,GOPROXY=off
,GOPROXY=file:///filesystem/path
,go mod vendor
,和go mod download
。
这些选项的详细信息遍及整个官方文档。此处是一个社区,试图对与这些行为相关的旋钮进行综合概述,其中包括指向官方文档的连接,以获取更多信息。
最简单的方法可能只是设置环境变量GO111MODULE=on
,该变量应适用于大多数CI系统。
可是,因为您的某些用户还没有选择加入模块,所以在启用和禁用模块的Go 1.11上的CI中运行测试可能颇有价值。vendor也是要考虑的话题。
如下两个博客文章更具体地介绍了这些主题:
该模块系统记录您的精确的依赖要求go.mod
。(有关更多详细信息,请参阅上面的go.mod概念部分或go.mod技巧文档)。
go mod tidy
更新您的当前信息,go.mod
以在模块中包括测试所需的依赖关系-若是测试失败,咱们必须知道使用了哪些依赖关系来重现失败。
go mod tidy
还能够确保您的当前go.mod
反映了操做系统,架构的全部可能组合的依赖性需求,并创建标签(如描述在这里)。相比之下,其余的命令同样go build
,并go test
只更新go.mod
提供电流下被请求包导入的包GOOS
,GOARCH
和创建标签(这是一个缘由go mod tidy
想补充一点,没有被要求添加go build
或相似)。
若是您模块的依赖项自己不具备go.mod
(例如,由于该依赖项还没有选择加入模块自己),或者其go.mod
文件缺乏其一个或多个依赖项(例如,因为模块做者未运行go mod tidy
) ,那么缺乏的传递依赖将被添加到您的模块的要求,与沿// indirect
注释,代表依赖是否是从你的模块中的直接进口。
请注意,这还意味着直接或间接依赖项中缺乏的任何测试依赖项也将记录在go.mod
。(如下状况很重要的示例:对模块go test all
的全部直接和间接依赖项进行测试,这是验证您当前版本组合是否能够协同工做的一种方法。若是在运行时测试在您的一种依赖项中失败go test all
,重要的是要记录一整套测试依赖项信息,以便您具备可重现的go test all
行为。
// indirect
您的go.mod
文件中可能具备依赖项的另外一个缘由是,若是您已经升级(或降级了)一个间接依赖项,超出了直接依赖项所要求的范围(例如,运行go get -u
或)go get foo@1.2.3
。go工具须要一个位置来记录这些新版本,而且它会在您的go.mod
文件中记录(而且不会深刻到您的依赖项中来修改其 go.mod
文件)。
一般,上述行为是模块如何经过记录精确的依赖项信息来提供100%可复制的构建和测试的一部分。
若是你是好奇,为何一个特定的模块,显示在你起来go.mod
,你能够运行go mod why -m <module>
于回答这个问题。用于检查需求和版本的其余有用工具包括go mod graph
和go list -m all
。
不,go.sum
不是锁定文件。go.mod
构建中的文件为100%可复制的构建提供了足够的信息。
为了进行验证,go.sum
包含特定模块版本的内容的预期密码校验和。有关详细信息(包括为何一般须要签入)以及技巧文档中的“模块下载和验证”部分,请参见下面的FAQ。go.sum
go.sum
部分因为go.sum
不是锁文件,所以即便您中止使用模块或特定模块版本,它也会保留模块版本的加密校验和。若是您之后继续使用某些内容,则能够验证校验和,从而提升了安全性。
另外,您的模块go.sum
记录了构建中使用的全部直接和间接依赖项的校验和(所以,go.sum
列出的模块一般比的要多go.mod
)。
一般,模块的go.sum
文件应与go.mod
文件一块儿提交。
go.sum
包含特定模块版本内容的预期密码校验和。go.sum
。go mod verify
检查磁盘下载的模块下载在磁盘上的缓存副本是否仍与中的条目匹配go.sum
。go.sum
它不是某些替代性依赖项管理系统中使用的锁定文件。(go.mod
为可复制的构建提供足够的信息)。go.sum
。有关更多详细信息,请参见技巧文档的“模块下载和验证”部分。请参阅#24117和#25530中讨论的未来可能的扩展。是。这支持在GOPATH以外进行工做,帮助与您选择模块的生态系统进行通讯,此外module
,您的指令还能够go.mod
用做代码身份的明确声明(这是最终不建议使用导入注释的缘由之一) )。固然,模块在Go 1.11中纯粹是可选功能。
请参阅上面的“语义导入版本控制”概念部分中有关语义导入版本控制和导入兼容性规则的讨论。另请参阅宣布提案的博客文章,其中更多地讨论了导入兼容性规则的动机和理由。
请参阅问题“为何导入路径中省略了主要版本v0,v1?” 在较早的FAQ中,来自官方提案的讨论。
在回应有关“ k8发行次要版本,但在每一个次要版本中更改Go API”的评论时,Russ Cox作出如下回应,着重强调了选择v0,v1与频繁使用v2,v3,v4进行重大更改的一些含义。 ,等等。
我并不彻底了解k8s开发周期等,可是我认为一般k8s团队须要决定/确认他们打算向用户保证稳定性的内容,而后相应地应用版本号来表达这一点。
- 要保证有关API兼容性(这彷佛是最佳的用户体验!),而后开始使用1.XY
- 为了灵活地在每一个发行版中进行向后不兼容的更改,但容许大型程序的不一样部分按不一样的时间表升级其代码,这意味着不一样的部分能够在一个程序中使用API的不一样主要版本,而后使用XY0,以及导入路径,例如k8s.io/client/vX/foo。
- 为了避免保证API兼容,而且不管什么状况,每一个构建都只须要一个k8s库的副本,这意味着即便不是全部构建都准备好了,构建的全部部分也必须使用相同版本。 ,而后使用0.XY
与此相关的是,Kubernetes具备一些非典型的构建方法(当前在Godep之上包括自定义包装脚本),所以Kubernetes对于许多其余项目来讲是不完善的示例,可是随着Kubernetes向采用Go 1.11迈进,这多是一个有趣的示例。模块。
是。
若是存储库未选择使用模块,但已使用有效的语义化版本号标签(包括所需的前导v
)进行了标记,则能够在中使用这些语义化版本号标签go get
,而且相应的语义化版本号版本将记录在导入模块的go.mod
文件中。若是存储库没有任何有效的语义化版本号标签,则将使用“伪版本”记录存储库的版本,例如 v0.0.0-20171006230638-a6e239ea1c69
(其中包括时间戳和提交哈希,而且其设计目的是容许对记录在其中的各个版本进行总排序)go.mod
并使其更容易推断出哪一个记录版本比另外一个记录版本“晚”。
例如,若是foo
标记了软件包的最新版本,v1.2.3
但foo
自身还没有选择加入模块,则在模块M的内部运行go get foo
或go get foo@v1.2.3
从模块M记录的内容将记录为模块M的go.mod
文件,以下所示:
require foo v1.2.3
该go
工具还将在其余工做流程中为非模块程序包使用可用的语义化版本号标记(例如go list -u=patch
,将模块的依赖项升级到可用的补丁程序版本,或将go list -u -m all
,显示可用的升级等)。
有关还没有选择模块的v2 +软件包的更多详细信息,请参见下一个常见问题解答。
是的,模块能够导入还没有选择模块的v2 +软件包,而且若是导入的v2 +软件包具备有效的语义化版本号标签,则将记录+incompatible
后缀。
额外细节
请熟悉上面“语义导入版本控制”部分中的材料。
首先回顾一些一般有用但在考虑本FAQ中描述的行为时要记住的特别重要的核心原则会有所帮助。
当工具以模块模式(例如)运行时,如下核心原则始终是正确的:go
GO111MODULE=on
/vN
被视为v1或v0模块(即便导入的程序包未选择加入模块而且具备表示主要版本大于1的VCS标记,也是如此)。module foo/v2
开头声明的模块路径(例如)go.mod
均为:
咱们将在接下来的FAQ看到,当这些原则并不老是正确的go
工具是不是在模块模式,可是当这些原则是老是正确的go
工具是模块模式。
简而言之,+incompatible
后缀表示当知足如下条件时,上述原则2有效:
/vN
被视为v1或v0模块(即便VCS标签另有说明)当go
工具处于模块模式时,它将假定非模块v2 +软件包不了解语义导入版本控制,并将其视为该软件包的v1版本系列的(不兼容)扩展(而且+incompatible
后缀表示go
工具正在这样作)。
例
假设:
oldpackage
是一个在引入模块以前的软件包oldpackage
从未选择使用模块(所以自己没有模块go.mod
)oldpackage
具备有效的语义化版本号标签v3.0.1
,这是它的最新标签在这种状况下,例如go get oldpackage@latest
从模块M内部运行将在模块M的go.mod
文件中记录如下内容:
require oldpackage v3.0.1+incompatible
请注意,在上面的命令或记录的指令/v3
的末尾没有使用– 在模块路径和导入路径中使用是语义导入版本控制的功能,而且未表示接受并理解了语义导入版本控制(还没有给出)经过在其内部包含文件来选择加入模块。换句话说,即便具备语义化版本号标签,也不会被授予语义导入版本控制的权利和责任(例如,在导入路径中使用),由于还没有声明要这样作。oldpackage
go get
require
/vN
oldpackage
oldpackage
go.mod
oldpackage
oldpackage
v3.0.1
oldpackage
/vN
oldpackage
该+incompatible
后缀代表该v3.0.1
版本oldpackage
并无主动选择加入的模块,所以v3.0.1
版本oldpackage
被认为不理解语义进口版本或如何使用进口路径主要版本。所以,在模块模式下运行时,该go
工具会将的非模块v3.0.1
版本oldpackage
视为的v1版本系列的(不兼容)扩展,oldpackage
并假定的v3.0.1
版本oldpackage
不了解语义导入版本控制,而且+incompatible
后缀表示该go
工具正在这样作。
该事实v3.0.1
的版本oldpackage
被认为是根据语义进口版本的v1发行版系列的一部分意味着,例如版本v1.0.0
,v2.0.0
以及v3.0.1
使用相同的导入路径都始终输入:
import "oldpackage"
再次注意,/v3
末尾没有用过oldpackage
。
一般,具备不一样导入路径的软件包是不一样的软件包。在这个例子中,给出的版本v1.0.0
,v2.0.0
和v3.0.1
中oldpackage
会使用相同的导入路径须要进口,所以它们是经过构建视为同一包(也由于oldpackage
在尚未选择到语义进口版本),以单拷贝oldpackage
最终在任何给定的版本中。(使用的版本在任何require
指令中在语义上都是最高的版本;请参见“版本选择”)。
若是咱们假设稍后建立一个新的v4.0.0
发行版,oldpackage
该发行版采用模块并所以包含一个go.mod
文件,则该信号oldpackage
如今能够理解语义导入版本控制的权利和责任,所以基于模块的使用者如今能够/v4
在导入中使用导入路径:
import "oldpackage/v4"
该版本将记录为:
require oldpackage/v4 v4.0.0
oldpackage/v4
如今的导入路径不一样于oldpackage
,所以包也不一样。若是构建中的某些使用方拥有import "oldpackage/v4"
同一个构建中的其余使用方,则两个副本(每一个导入路径一个)将最终生成一个支持模块的构建import "oldpackage"
。做为容许逐步采用模块的策略的一部分,这是理想的。另外,即便在模块退出其当前过渡阶段以后,也但愿此行为容许随着时间的推移逐步进行代码演化,其中不一样的使用者以不一样的速率升级到较新版本(例如,容许大型版本中的不一样使用者选择升级)从不一样的速率oldpackage/v4
一些将来oldpackage/v5
)。
在考虑还没有加入模块的较旧的Go版本或Go代码时,语义导入版本控制具备与v2 +模块相关的显着向后兼容性含义。
如上文“语义导入版本控制”部分所述:
/vN
在声明的其本身的模块路径中包含go.mod
。/vN
在导入路径中包含,以导入v2 +模块。可是,预计生态系统将以不一样的采用模块和语义导入版本控制的速度进行。
如“如何释放v2 +模块”部分中更详细描述的那样,在“主要子目录”方法中,v2 +模块的做者建立了诸如mymodule/v2
或的子目录,mymodule/v3
并在这些子目录下移动或复制了相应的软件包。这意味着传统的导入路径逻辑(即便在旧的Go版本中,如Go 1.8或1.7)也会在看到诸如的导入语句时找到合适的软件包import "mymodule/v2/mypkg"
。所以,即便未启用模块支持,也能够找到并使用“主要子目录” v2 +模块中的软件包(这是由于您正在运行Go 1.11且未启用模块,仍是由于您正在运行旧版本,如Go)没有完整模块支持的1.七、1.八、1.9或1.10)。请看“如何发布v2 +模块”部分提供了有关“主要子目录”方法的更多详细信息。
该常见问题解答的其他部分集中于“如何发布v2 +模块”部分中介绍的“主要分支”方法。在“主要分支”方法中,不/vN
建立任何子目录,而是经过go.mod
文件并经过将语义化版本号标签应用于提交来传达模块版本信息(一般在上master
,但能够在不一样的分支上)。
为了在当前过渡时期提供帮助,Go 1.11 引入了“最小模块兼容性” ,觉得还没有加入模块的Go代码提供更大的兼容性,而且“最小模块兼容性”也被反向移植到Go 1.9。 7和1.10.3(鉴于那些旧版Go版本不具备完整模块支持,这些版本始终在禁用完整模块模式的状况下始终有效运行)。
“最小模块兼容性”的主要目标是:
容许较早的Go版本1.9.7+和1.10.3+可以更轻松地编译/vN
在导入路径中使用语义导入版本控制的模块,并在Go 1.11中禁用模块模式时提供相同的行为。
容许旧代码可以使用v2 +模块,而无需使用旧的消费者代码在使用/vN
v2 +模块时当即更改成使用新的导入路径。
这样作无需依赖模块做者便可建立/vN
子目录。
其余详细信息–“最小模块兼容性”
“最小模块兼容性”仅在禁用该工具的完整模块模式时才生效go
,例如,若是您GO111MODULE=off
在Go 1.11中进行了设置,或者正在使用Go 1.9.7+或1.10.3+版本。
当v2 +模块做者还没有建立/v2
或建立/vN
子目录时,您转而依赖于Go 1.9.7 +,1.10.3 +和1.11中的“最小模块兼容性”机制:
go
工具在全模块模式下运行时,它将不会导入该模块的v2 +版本。(假定已选择使用模块的软件包“说”语义导入版本控制。若是foo
是具备v2 +版本的模块,则在“语义导入版本控制”下表示import "foo"
要导入的v1语义导入版本控制系列foo
)。/vN
在删除后,将再次尝试包含a的没法解析的导入语句带有有效文件)。/vN
.go
go.mod
import "foo/v2"
位于模块内部的代码内)仍将在GOPATH模式下(分别为1.9.7 +,1.10.3 +和1.11)正确编译,而且将像说的那样进行解析import "foo"
(不带/v2
) ,这意味着它将使用foo
驻留在您的GOPATH中的版本,而不会被多余的混淆/v2
。go
命令行中使用的路径(例如go get
或的参数go list
)。/vN
对v2 +模块使用新的导入。import "foo/v2"
出如今基于模块的代码中将解析为与您的GOPATH中驻留的代码相同的代码import "foo"
,而且该构建最终以-的一个副本结尾foo
-特别是不管GOPATH磁盘上的版本如何。这使得基于模块的代码 import "foo/v2"
甚至能够在1.9.7 +,1.10.3 +和1.11的GOPATH模式下进行编译。go
工具以全模块模式运行时:
go
工具处于完整模块模式而且foo
是v2 +模块,则import "foo"
要求提供foo
vs 的v1版本,import "foo/v2"
要求提供的v2版本foo
。语义化版本号是模块系统的基础。为了向消费者提供最佳体验,鼓励模块做者使用语义化版本号 VCS标签(例如v0.1.0
或v1.2.3-rc.1
),但严格要求不使用语义化版本号 VCS标签:
要求模块遵循语义化版本号规范,以使该go
命令按照记录的方式运行。这包括遵循关于如何以及什么时候容许更改的语义化版本号规范。
消费者使用伪版本形式的语义化版本号版本记录没有语义化版本号 VCS标签的模块。一般,这将是v0主版本,除非模块做者遵循“主子目录”方法构造了v2 +模块。
所以,不该用语义化版本号 VCS标记且未建立“主要子目录”的模块将有效地声明本身属于语义化版本号 v0主版本系列,而且基于模块的使用者将其视为具备语义化版本号 v0主版本。
一个模块能够依赖于其自身的不一样主要版本:总的来讲,这至关于依赖于不一样的模块。出于各类缘由,这可能颇有用,包括容许将模块的主要版本实现为围绕其余主要版本的填充程序。
此外,一个模块能够在一个周期中依赖于其自身的不一样主要版本,就像两个彻底不一样的模块能够在一个周期中彼此依赖同样。
可是,若是您不但愿模块依赖于其自身的不一样版本,则多是错误的征兆。例如,打算从v3模块导入软件包的.go代码可能缺乏/v3
import语句中所需的内容。根据自己的v1版本,该错误可能表现为v3模块。
若是您惊讶地看到一个模块依赖于其自身的不一样版本,那么值得回顾一下上面的“语义导入版本控制”部分以及常见问题解答“若是我没有看到预期的版本,该怎么办?依赖?” 。
两个程序包可能在一个周期中彼此不依赖仍然是一个约束。
多模块存储库是一个包含多个模块的存储库,每一个模块都有本身的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中评论:
对于除电源用户之外的全部用户,您可能但愿采用一种惯例,即一个repo =一个模块。对于代码存储选项的长期发展很重要,一个仓库能够包含多个模块,可是默认状况下您几乎确定不想这样作。
关于如何使多模块更有效的两个示例:
go test ./...
从存储库根目录开始将再也不测试存储库中的全部内容replace
指令按期管理模块之间的关系。可是,除了这两个示例以外,还有其余细微差异。若是您考虑在单个存储库中包含多个模块,请仔细阅读本小节中的FAQ 。
有两个示例场景,其中go.mod
一个存储库中可能有多个合理的场景:
若是您有一些使用示例,其中这些示例自己具备一组复杂的依赖关系(例如,也许您的软件包很小,但包括一个将软件包与kubernetes结合使用的示例)。在这种状况下,对于您的存储库来讲,拥有一个examples
或一个_examples
本身的目录是颇有意义的go.mod
,例如here。
若是您的存储库具备一组复杂的依赖关系,可是您的客户端API的依赖关系集较少。在某些状况下,拥有一个api
或一个或clientapi
多个具备本身的目录go.mod
或将其分隔clientapi
到本身的存储库中多是有意义的。
可是,对于这两种状况,若是您考虑为多组间接依赖项建立性能或下载大小的多模块存储库,则强烈建议您首先尝试使用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,让咱们经过上面的存储库逐步进行操做:
添加github.com/my-repo/mig/go.mod:
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
git commit
git tag v1.3.0
git tag mig/v1.0.0
接下来,让咱们测试一下。咱们不能go build
仍是go test
天真地作,由于go命令会尝试从模块缓存中获取每一个相关模块。所以,咱们须要使用替换规则来使go
命令使用本地副本:
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
git push origin master v1.2.4 mig/v1.0.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
在单个存储库中具备多个文件的另外一个用例是,若是存储库中的文件应从模块中删除。例如,存储库可能具备Go模块不须要的很是大的文件,或者多语言存储库可能具备许多非Go文件。
go.mod
目录中的空白将致使该目录及其全部子目录从顶级Go模块中排除。
若是排除的目录不包含任何.go
文件,则除了放置空go.mod
文件以外,不须要其余步骤。若是排除的目录中确实包含.go
文件,请首先仔细阅读此多模块存储库部分中的其余常见问题解答。
请参阅问题“最小版本选择是否会使开发人员没法得到重要更新?” 在较早的FAQ中,来自官方提案的讨论。
go env
来确认是否启用了模块,以确认其未为只读GOMOD
变量显示空值。
GOMOD
为变量,由于它其实是输出的只读调试go env
输出。GO111MODULE=on
要启用模块,请仔细检查它是否不是复数形式GO111MODULES=on
。(人们有时天然会包括,S
由于该功能一般称为“模块”)。-mod=vendor
标志是否正在传递给go build
或传递给该标志或已GOFLAGS=-mod=vendor
被设置。
vendor
目录,除非您要求go
使用该工具vendor
。go list -m all
查看为您的构建选择的实际版本列表 一般会颇有帮助
go list -m all
与仅查找go.mod
文件相比,一般能够提供更多详细信息。go get foo
因某种go build
缘由而失败,或者特定软件包失败foo
,则一般能够检查go get -v foo
或的输出go get -v -x foo
:
go get
一般会提供比更为详细的错误消息go build
。-v
标志go get
要求打印更多详细信息,但请注意,根据配置远程存储库的方式,某些“错误”(例如404错误)可能会发生。go get -v -x foo
,它也显示了git或其余已发布的VCS命令。(若是有保证,您一般能够在go
工具的上下文以外执行相同的git命令以进行故障排除)。vgo
原型和Go 1.11 beta 的常见问题根源,但在GA 1.11中则不多出现。go
并行执行多个命令(请参阅#26794,Go 1.12已解决)。做为故障排除步骤,您能够将$ GOPATH / pkg / mod复制到备份目录(以防稍后须要进一步调查),运行go clean -modcache
,而后查看原始问题是否仍然存在。当前正在检查的错误多是因为构建中没有特定模块或软件包的预期版本而引发的第二个问题。所以,若是致使特定错误的缘由不明显,则能够按照下一个FAQ中的说明对您的版本进行抽查。
一个好的第一步是运行go mod tidy
。这可能会解决问题,但也有可能使您的go.mod
文件相对于.go
源代码处于一致状态,这将使之后的调查更加容易。(若是go mod tidy
它自己以某种您不但愿的方式更改了依赖关系的版本,请先阅读'go mod tidy'上的常见问题解答。若是仍没法解决,您能够尝试重置您的go.mod
,而后运行go list -mod=readonly all
,这可能会带来更多的变化。有关须要更改其版本的特定消息)。
第二步一般应检查go list -m all
以查看为您的构建选择的实际版本列表。 go list -m all
向您显示最终选择的版本,包括用于间接依赖性的版本以及在解决全部共享依赖性的版本以后的版本。它还显示any replace
和exclude
指令的结果。
下一步是检查go mod graph
或的输出go mod graph | grep <module-of-interest>
。 go mod graph
打印模块需求图(包括考虑的更换)。输出中的每一行都有两个字段:第一列是使用模块,第二列是该模块的要求之一(包括该使用模块所需的版本)。这是查看哪些模块须要特定依赖项的快速方法,包括当构建的依赖项具备与构建中的不一样使用者不一样的所需版本时(若是是这种状况,熟悉该模块很重要)。行为在上面的“版本选择”部分中进行了说明)。
go mod why -m <module>
在这里也能够是有用的,尽管一般对于查看为何彻底包含依赖项(而不是为何依赖项以特定版本结束)更为有用。
go list
提供了更多的查询变体,在须要时能够用于查询模块。如下是一个示例,它将显示构建中使用的确切版本,不包括仅测试依赖项:
go list -deps -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' ./... | sort -u
用于询问你的模块的更详细的命令集和实施例的可以在可运行“转到模块经过实施例”中能够看出walkthough。
致使意外版本的一个缘由多是因为某人建立了一个go.mod
非预期的无效或意外文件,或者是相关的错误(例如:一个v2.0.1
模块版本可能错误地将自身声明为module foo
在其中,go.mod
而没有必要/v2
; import语句)在.go
打算导入v3的模块可能缺乏所需的代码/v3
;一require
在一份声明中go.mod
对V4模块可能缺乏必要的/v4
)。所以,若是您看不到引发特定问题的缘由,那么值得首先阅读“ go.mod”和“语义导入版本控制”中的材料上面的部分(考虑到这些包括模块必须遵循的重要规则),而后花几分钟来检查最相关的go.mod
文件和import语句。
这是一条常见的错误消息,可能会因几种不一样的根本缘由而发生。
在某些状况下,此错误仅是因为路径键入错误引发的,所以第一步可能应该是根据错误消息中列出的详细信息再次检查错误的路径。
若是您尚未这样作,那么下一步一般是尝试go get -v foo
如下操做go get -v -x foo
:
go get
一般会提供比更为详细的错误消息go build
。其余一些可能的缘由:
cannot find module providing package foo
若是您已发出go build
或在当前目录中go build .
没有.go
任何源文件,则可能会看到错误。若是这是您遇到的问题,则解决方案多是另外一种调用,例如go build ./...
(其中./...
展开以匹配当前模块中的全部软件包)。参见#27122。
Go 1.11中的模块缓存可能致使此错误,包括面对网络问题或go
并行执行的多个命令。这在Go 1.12中已解决。有关更多详细信息和可能的纠正步骤,请参阅上面本节中的第一个故障排除常见问题解答。
go mod init
没有任何参数的状况下,将根据不一样的提示(例如VCS元数据)尝试猜想正确的模块路径。可是,不能go mod init
老是可以猜想出正确的模块路径。
若是go mod init
给您这个错误,则这些试探法没法猜想,您必须本身提供模块路径(例如go mod init github.com/you/hello
)。
是。这须要一些手动步骤,但在某些更复杂的状况下可能会有所帮助。
在go mod init
初始化本身的模块时运行时,它将经过转换配置文件(如Gopkg.lock
,glide.lock
)或包含相应指令vendor.json
的go.mod
文件自动从先前的依赖项管理器转换require
。Gopkg.lock
例如,现有文件中的信息一般描述全部直接和间接依赖项的版本信息。
可是,若是改成添加还没有选择加入模块自己的新依赖项,则任何先前的依赖项管理器都不会使用相似的自动转换过程,而新的依赖项可能已经在使用该转换过程。若是该新依赖项自己具备发生了重大更改的非模块依赖项,则在某些状况下可能会致使不兼容问题。换句话说,新依赖项的先前依赖项管理器不会自动使用,在某些状况下,这可能会致使间接依赖项出现问题。
一种方法是go mod init
在有问题的非模块直接依赖项上运行,以从其当前的依赖项管理器进行转换,而后使用require
结果临时文件中的指令go.mod
填充或更新go.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
require
临时的结果信息go.mod
能够手动移至go.mod
模块的实际信息中,或者您能够考虑使用https://github.com/rogpeppe/gomodmerge,这是针对此用例的社区工具。另外,您将须要require github.com/some/nonmodule v1.2.3
在实际中添加一个go.mod
以匹配您手动克隆的版本。
在#28489注释中,针对Docker使用此技术的具体示例说明了如何获取一致的Docker依赖项版本集,从而避免github.com/sirupsen/logrus
vs. 之间区分大小写的问题github.com/Sirupsen/logrus
。
一般,模块go.mod
经过module
指令(例如)在其声明中声明其身份module example.com/m
。这是该模块的“模块路径”,而且该go
工具在该声明的模块路径与任何使用者使用的导入路径之间强制保持一致性。若是模块的go.mod
文件为module example.com/m
,则使用者必须使用以该模块路径开头的导入路径(例如import "example.com/m"
或import "example.com/m/sub/pkg"
)从该模块导入软件包。
若是使用者使用的导入路径与相应的声明模块路径不匹配,则该go
命令将报告parsing go.mod: unexpected module path
致命错误。另外,在某些状况下,该go
命令随后将报告更通用的error loading module requirements
错误。
致使此错误的最多见缘由是,是否进行了名称更改(例如github.com/Sirupsen/logrus
到github.com/sirupsen/logrus
),或者因为虚荣导入路径而致使模块有时在模块以前经过两个不一样的名称使用(例如github.com/golang/sync
vs.建议golang.org/x/sync
)。
若是您有一个依存关系仍经过较旧的名称(例如,github.com/Sirupsen/logrus
)或非规范名称(例如,github.com/golang/sync
)导入,可是该依赖关系随后采用了模块,而且如今在中声明了其规范名称,则可能会致使问题go.mod
。而后,当发现模块的升级版本声明再也不与旧的导入路径匹配的规范模块路径时,在升级期间会触发此错误。
github.com/Quasilyte/go-consistent
。github.com/quasilyte/go-consistent
(更改Q
为小写q
),这是一个重大更改。GitHub从旧名称转发到新名称。go get -u
,它将尝试升级全部直接和间接依赖项。github.com/Quasilyte/go-consistent
试图进行升级,可是最新go.mod
发现为module github.com/quasilyte/go-consistent
。转到:github.com/Quasilyte/go-consistent@v0.0.0-20190521200055-c6f3937de18c:解析go.mod:意外的模块路径“ github.com/quasilyte/go-consistent”转到:错误加载模块要求
错误的最多见形式是:
转到:example.com/some/OLD/name@vX.YZ:解析go.mod:意外的模块路径“ example.com/some/NEW/name”
若是您访问存储库的信息example.com/some/NEW/name
(从错误的右侧开始),则能够检查go.mod
文件的最新版本,或者master
查看它是否在go.mod
as 的第一行中声明了本身module example.com/some/NEW/name
。若是是这样,则暗示您看到的是“旧模块名称”与“新模块名称”的问题。
本节的其他部分重点在于按顺序执行如下步骤来解决此错误的“旧名称”和“新名称”形式:
检查您本身的代码,看看是否要使用导入example.com/some/OLD/name
。若是是这样,请更新您的代码以导入example.com/some/NEW/name
。
若是您在升级过程当中收到此错误,则应尝试使用Go的尖端版本进行升级,该尖端版本具备针对性更强的升级逻辑(#26902),一般能够回避此问题,而且在这种状况下一般还具备更好的错误消息。请注意,go get
tip / 1.13中的参数与1.12 中的参数不一样。获取提示并使用它升级依赖项的示例:
go get golang.org/dl/gotip && gotip download gotip get -u all gotip mod tidy
因为有问题的旧导入一般是间接依赖的,所以使用tip升级而后运行go mod tidy
能够常常将您升级为有问题的版本,而后从go.mod
再也不须要的版本中删除有问题的版本,这将使您进入正常运行状态返回到使用Go 1.12或1.11进行平常使用。例如,看到这种方法工做在这里升级过去github.com/golang/lint
与golang.org/x/lint
问题。
若是您在执行go get -u foo
或时收到此错误go get -u foo@latest
,请尝试删除-u
。这将为您提供一组所使用的依赖项,foo@latest
而无需升级发布foo
者foo
可能会验证为工做的过去版本的依赖项foo
。这在过渡时期可能很重要,在这种过渡时期,某些直接或间接的依赖关系foo
可能还没有采用语义化版本号或模块。(一个常见的错误是认为go get -u foo
仅获取的最新版本foo
。实际上,-u
in go get -u foo
或go get -u foo@latest
手段也获取的全部直接和间接依赖项的最新版本。foo
; 可能正是您想要的,但若是因为深层间接依赖而致使失败,则可能不会特别如此。
若是上述步骤不能解决错误,则下一种方法会稍微复杂一些,但大多数状况下应该能够解决此错误的“旧名称”和“新名称”形式。这仅使用仅来自错误消息自己的信息,并简要介绍了一些VCS历史记录。
4.1。转到example.com/some/NEW/name
存储库
4.2。肯定什么时候将go.mod
文件引入那里(例如,经过查看的责任或历史视图go.mod
)。
4.3。挑选释放或提交以前的go.mod
介绍有文件。
4.4。在您的go.mod
文件中,在replace
语句的两边添加一个使用旧名称的replace
语句: replace example.com/some/OLD/name => example.com/some/OLD/name <version-just-before-go.mod>
使用咱们先前的示例,其中哪里github.com/Quasilyte/go-consistent
是旧名称,又github.com/quasilyte/go-consistent
是新名称,咱们能够看到go.mod
最先是在commit 00c5b0cf371a中引入的。该存储库未使用语义化版本号标记,所以咱们将紧接以前的提交00dd7fb039e提交,并使用两边的旧大写Quasilyte名称将其添加到替换中replace
:
replace github.com/Quasilyte/go-consistent => github.com/Quasilyte/go-consistent 00dd7fb039e
replace
而后,该语句使咱们可以经过有效地防止在存在的状况下将旧名称升级为新名称,从而解决了有问题的“旧名称”与“新名称”不匹配的问题go.mod
。一般,经过go get -u
或相似方式进行升级如今能够避免该错误。若是升级完成,则能够检查是否有人仍在导入旧名称(例如go mod graph | grep github.com/Quasilyte/go-consistent
),若是没有导入,则replace
能够将其删除。(这常常起做用的缘由是,若是使用了旧的有问题的导入路径,升级自己可能会失败,即便升级完成后在最终结果中可能不会使用升级路径也是如此(在#30831中进行了跟踪)。
gotip
在上面的第2步中使用可能会发现有问题的进口商,但并不是在全部状况下均可以,尤为是对于升级(#30661)。若是不清楚是谁在使用有问题的旧导入路径进行导入,一般能够经过建立干净的模块高速缓存,执行触发错误的一个或多个操做,而后在模块高速缓存中查找旧的有问题的导入路径来找出答案。例如: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
最后,上述步骤集中于如何解决潜在的“旧名称”与“新名称”问题。可是,若是将a go.mod
放置在错误的位置或仅具备错误的模块路径,也会出现相同的错误消息。在这种状况下,导入该模块应始终失败。若是要导入刚刚建立且从未成功导入的新模块,则应检查go.mod
文件是否正肯定位,以及文件是否具备与该位置对应的正确模块路径。(最多见的方法是go.mod
每一个存储库使用单个go.mod
文件,并将单个文件放置在存储库根目录中,并使用存储库名称做为module
指令中声明的模块路径)。参见“ go.mod”
简而言之:
由于预构建的软件包是非模块构建的,因此不能重复使用。抱歉。如今禁用cgo或安装gcc。
仅在选择加入模块时(例如经过GO111MODULE=on
),这才是一个问题。有关其余讨论,请参见#26988。
import "./subdir"
吗?否。请参阅#26645,其中包括:
在模块中,最后有一个子目录的名称。若是父目录显示“模块m”,则子目录将导入为“ m / subdir”,而再也不是“ ./subdir”。
没有.go
文件的vendor
目录不会经过复制在目录内go mod vendor
。这是设计使然。
简而言之,撇开任何特定的vendor行为– go构建的整体模型是构建软件包所需的文件应位于包含.go
文件的目录中。
以cgo为例,修改其余目录中的C源代码不会触发重建,而是您的构建将使用陈旧的缓存条目。cgo文档如今包括:
请注意,对其余目录中文件的更改不会致使从新编译该软件包,所以,该软件包的全部非Go源代码应存储在软件包目录中,而不是子目录中。
社区工具https://github.com/goware/modvendor容许您轻松地将一整套.c,.h,.s,.proto或其余文件从模块复制到vendor
Director中。尽管这可能会有所帮助,可是若是您有一些须要的文件来构建包含该.go
文件的目录以外的文件,则必须格外当心,以确保整体上能够正确处理go编译(与vendor无关)。
请参阅#26366中的其余讨论。
传统vendor的另外一种方法是检入模块缓存。它最终可能会得到与传统vendor相似的好处,而且在某些方面最终会得到更高的保真度。将此方法解释为“经过示例执行模块” 演练。