代码仓库(VCS)
go
命令可以直接从版本控制存储库下载模块源代码和元数据。从 代理 下载模块通常更快,但如果代理不可用或代理无法访问模块的存储库(对于私有存储库通常如此),则需要直接连接到存储库。支持 Git、Subversion、Mercurial、Bazaar 和 Fossil。版本控制工具必须安装在 PATH
的目录中,以便 go
命令使用它。
要从源存储库而不是代理下载特定模块,请设置“GOPRIVATE”或“GONOPROXY”环境变量。要将 go
命令配置为直接从源存储库下载所有模块,请将 GOPROXY
设置为 direct
。有关详细信息,请参阅 环境变量。
查找模块路径的存储库
当 go
命令以 direct
模式下载模块时,它首先会定位包含该模块的存储库。
如果模块路径在路径组件的末尾有 VCS 限定符(.bzr
、.fossil
、.git
、.hg
、.svn
之一),go
命令将使用该路径限定符之前的所有内容作为存储库 URL。例如,对于模块 example.com/foo.git/bar
,go
命令使用 git 在 example.com/foo.git
下载存储库,期望在 bar
子目录中找到该模块. go
命令将根据版本控制工具支持的协议猜测要使用的协议。
如果模块路径没有限定符,go
命令会向从模块路径派生的 URL 发送 HTTP GET
请求,并带有 ?go-get=1
查询字符串。例如,对于模块 golang.org/x/mod
,go
命令可能会发送以下请求:
https://golang.org/x/mod?go-get=1(首选)
http://golang.org/x/mod?go-get=1(回退,仅适用于 GOINSECURE)
go
命令遵循重定向,但会忽略响应状态代码,因此服务器可能会以 404 或任何其他错误状态进行响应。 GOINSECURE
环境变量可以设置为允许回退和重定向到特定模块的未加密 HTTP。
服务器必须使用在文档的 <head>
中包含 <meta>
标记的 HTML 文档进行响应。 <meta>
标签应该出现在文档的前面,以避免混淆 go
命令的限制解析器。特别是,它应该出现在任何原始 JavaScript 或 CSS 之前。 <meta>
标签必须采用以下形式:
<meta name="go-import" content="root-path vcs repo-url">
root-path
是存储库根路径,模块路径中对应于存储库根目录的部分。它必须是所请求模块路径的前缀或完全匹配。如果不是完全匹配,则会再次请求前缀以验证 <meta>
标签匹配。
vcs
是版本控制系统。它必须是下表中列出的工具之一或关键字 mod
,它指示 go
命令使用 GOPROXY
协议从给定的 URL 下载模块)。有关详细信息,请参阅直接从代理提供模块。
repo-url
就是代码仓库的下载URL. 如果这个URL不包含scheme信息(因为模块路径具有VCS限定符,或者是因为<meta>
tag 缺失scheme), go
命令将会尝试所有支持的版本控制系统协议. 例如,对于 Git, go
命令将首先尝https://
然后才是 git+ssh://
. 对于不安全的版本控制系统协议 (比如 http://
和 git://
)只有在GOINSECURE
环境变量和 module path 匹配的情况下才可能被使用。
Name | Command | GOVCS default | Secure schemes |
---|---|---|---|
Bazaar | bzr |
Private only(仅私有) | https , bzr+ssh |
Fossil | fossil |
Private only(仅私有) | https |
Git | git |
Public and private(私有和公共) | https , git+ssh , ssh |
Mercurial | hg |
Public and private (私有和公共) | https , ssh |
Subversion | svn |
Private only(仅私有) | https , svn+ssh |
举例来说, repo-url
设置为 golang.org/x/mod
时候. go
命令执行请求https://golang.org/x/mod?go-get=1
. 在server端则会返回一段HTML并携带tag信息:
<meta name="go-import" content="golang.org/x/mod git https://go.googlesource.com/mod">
接收到response后, go
命令将会使用https://go.googlesource.com/mod
作为 Git repository.
GitHub 和其他流行的托管服务在响应?go-get=1
时候会去查询所有的repositories信息,所以没有一个配置来约束modules和站点的关系。
在获取到repository URL之后,go
命令将 repository
信息存放进 module cache
中。一般来说,go
会去处理掉一些无效或者冗余的依赖数据。但是实际使用的命令会因版本控制系统而异,也可能会随着时间而变化。对于git
而言,go
命令可以列大多数可用的版本而不去下载。通常下我们会去下载最新的版本,而忽略较老的版本。
映射版本提交
go
命令可以在特定规范版本中查看存储库中的模块,如v1.2.3
,v2.4.0-beta
,或v3.0.0+incompatible
。每个模块版本应在存储库中具有语义版本标记,表示应检查给定版本的哪个修订。
如果在存储库根目录中或根目录的主要版本子目录中定义了模块,则每个版本标记名称等于相应版本。例如,模块golang.org/x/text
在其存储库的根目录中定义,因此版本v0.3.2
具有标记v0.3.2
在该存储库中。对于大多数模块,这是正确的。
如果模块在存储库中的子目录中定义,即模块路径的module子目录部分不为空,则每个标记名称必须使用模块子目录前缀,然后是斜杠。例如,模块golang.org/x/tools/gopls
在带有根路径golang.org/x/tools
的存储库的gopls
子目录中定义。该模块的版本v0.4.0
必须使标记名为gopls/v0.4.0
的标记。
语义版标记的主要版本号必须与模块路径的主要版本后缀(如果有)一致。例如,标签v1.0.0
可以属于模块example.com/mod
但不是example.com/mod/v2
,因它具有标签像v2.0.0
。
具有主要版本v2
或更高版本的标签可以属于没有主要版本后缀的模块,如果没有go.mod
文件,并且模块位于存储库根目录中。这种版本用后缀+incompatible
表示。版本标记本身不得具有后缀。请参阅与non-module存储库的兼容性。
创建标签后,不应删除或更改为不同的修订版。版本是认证的,以确保安全,可重复的构建。如果修改了标记,则在下载时,客户端可能会看到安全错误。即使在删除标记之后,其内容也可能在module代理上可用。
映射伪版本以提交
go
命令可以在特定修订版中查看存储库中的模块,编码为伪版本 如 v1.3.2-0.20191109021931-daa7c04131f5
。
伪版本的最后12个字符(上面示例中的daa7c04131f5
)指示存储库中的修订。这意味着取决于版本控制系统。对于Git和Mercurial,这是一个提交哈希的前缀。对于子版本,这是一个零填充修订号。
在签出提交之前,go
命令验证时间戳(20191109021931
上面)匹配提交日期。它还验证基本版本(v1.3.1
,在上面的示例中v1.3.2
之前的版本)对应于是提交的祖先的语义版本标记。这些检查确保模块作者完全控制伪版本与其他发布版本的比较。
有关详细信息,请参阅伪版本。
映射分支并提交版本
可以使用版本查询在特定分支,标签或修订上签出模块。
go get example.com/mod@master
go
命令将这些名称转换为规范版本,这些名称可以与最小版本选择(mvs)一起使用。 MVS取决于明确订购版本的能力。分支名称和修订无法随时间可靠地比较,因为它们依赖于可能改变的存储库结构。
如果使用像v1.2.3
等一个或多个语义版标记标记的修订版,则将使用最高有效版本的标记。go
命令仅考虑可能属于目标模块的语义版标签;例如,标签v1.5.2
不会考虑example.com/mod/v2
,因为主要版本与模块路径的后缀不匹配。
如果没有用有效的语义版本标记标记修订版,则go
命令将生成伪版本。如果修订具有具有有效语义版本标签的祖先,则最高的祖先版本将被用作伪版本基础。见伪版本。
存储库中的模块目录
一旦在特定修订版中检查了模块的存储库,go
命令必须找到包含模块的go.mod
文件(模块的根目录)的目录。
回想一下,module路径 由三个部分组成:存储库根路径(对应于存储库根目录),模块子目录和主要版本后缀(仅适用于在v2
或更高版本的模块)。
对于大多数模块,模块路径等于存储库根路径,因此模块的根目录是存储库的根目录。
模块有时在存储库子目录中定义。这通常是为具有需要独立释放和版本的多个组件的大型存储库来完成。预计这样的模块将在存储库根路径之后与模块路径的一部分匹配的子目录中找到。例如,假设模块example.com/monorepo/foo/bar
在带有根路径example.com/monorepo
的存储库中。它go.mod
文件必须在foo/bar
子目录中。
如果模块在主要版本v2
或更高版本中释放,则其路径必须具有主要版本后缀。具有主要版本后缀的模块可以在两个子目录之一中定义:一个带有后缀,一个没有。例如,假设使用路径example.com/monorepo/foo/bar/v2
释放上面的新版本。它的go.mod
文件可以在foo/bar
或foo/bar/v2
中。
具有主要版本后缀的子目录是主要版本子目录。它们可用于在单个分支上开发多个主要版本的模块。当多个主要版本的开发在单独的分支上进行时,这可能是不必要的。但是,主要版本子目录具有重要属性:在GOPATH
模式下,包导入路径完全匹配 GOPATH/src
下的目录。go
命令在GOPATH
模式下提供最小的模块兼容性(参见与non-module存储库的兼容性),因此主要版本的子目录并不总是与内置于GOPATH
模式内置的项目的兼容性所必需的。不支持最小模块兼容性的旧工具可能存在问题。
一旦go
命令已经找到了模块根目录,它会创建一个.zip
文件的目录内容,然后从.zip
文件中提取到模块缓存。有关可能包含在.zip
文件中,请参阅文件路径和大小约束 。.zip
文件的内容是认证在提取到模块缓存之前,与从代理下载.zip
文件的方式相同。
模块zip文件不包括vendor
目录或任何嵌套模块的内容(包含go.mod
文件的子目录)。这意味着模块必须注意不要引用其目录外或其他模块之外的文件。例如,//go:embed
模式不得匹配嵌套模块中的文件。此行为可以在文件不包括在模块中的情况下作为有用的解决方法。例如,如果存储库将大文件留到testdata
目录中,则模块作者可以在testdata
中添加一个空的go.mod
文件。因此,他们的用户不需要下载这些文件。当然,这可能会减少测试其依赖性的用户的覆盖范围。
许可证文件的特殊情况
当go
命令创建一个不在存储库根目录中的模块的.zip
文件时,如果模块没有名为LICENSE
的文件,则它在根目录中(与go.mod
一起),如果它在同一版本中存在,go
命令将复制名为LICENSE
的文件。
此特殊情况允许相同的LICENSE
文件应用于存储库中的所有模块。这仅适用于名为LICENSE
的文件,具体而言,没有扩展,如.txt
。不幸的是,如果没有破坏出消耗模块的加密和,就无法扩展;请参阅Authenticating modules。其他工具和网站(如pkg.go.dev)可以使用其他名称识别文件。
还要注意,go
命令不包括创建模块.zip
文件时的符号链接;请参见文件路径和大小约束。因此,如果存储库在其根目录中没有LICENSE
文件,则作者可以在子目录中定义的模块中创建其许可证文件的副本,以确保模块.zip
中包含这些文件。
使用GOVCS
控制版本控制工具
go
命令用Version Control命令下载模块的能力,如git
对分散的包生态系统至关重要,其中可以从任何服务器导入代码。如果恶意服务器找到导致调用版本控制命令运行意外代码的方法,它也是一个潜在的安全问题。
为了平衡功能和安全问题,默认情况下go
命令只会使用git
和hg
来从公共服务器下载代码。它将使用任何已知的版本控制系统从私有服务器下载代码,定义为匹配 GOPRIVATE
环境的托管包变量。只有Git和Mercurial允许的理由是这两个系统最关注作为不受信任的服务器的客户运行的问题。相比之下,集市,化石和颠覆主要用于可信赖的身份验证的环境中,并且并不像攻击表面仔细审查。
版本控制命令限制仅适用于使用直接版本控制访问来下载代码时。从代理下载模块时,go
命令使用GOPROXY
协议,它始终是允许。默认情况下,go
命令使用go模块镜像(proxy.golang.org),只能返回私人的版本控制模块或镜子拒绝服务公共包裹(通常出于法律原因)。因此,客户端仍可默认访问来自集市,化石或颠覆存储库服务的公共代码,因为这些下载使用Go模块镜像,这是使用自定义沙箱运行版本控制命令的安全风险。
GOVCS
变量可用于改变特定模块的允许的版本控制系统。 GOVCS
变量在模块感知模式和GOPATH模式下构建包时适用。使用模块时,模式匹配模块路径。使用GOPATH时,模式与对应于版本控制存储库的根的导入路径匹配。
GOVCS
变量的一般形式是逗号分离的pattern:vcslist
规则。模式是一个glob模式,必须匹配模块或导入路径的一个或多个前导元素。 vcslist是一个允许的允许版本控制命令的竖线分离列表,或者all
,以允许使用任何已知的命令,或off
以允许任何内容。请注意,如果模块与vcslist off
的模式匹配,则如果原始服务器使用mod
方案,则可能仍可下载它,该方案指示Go命令下载模块使用GOPROXY
协议。列表中最早的匹配模式适用,即使稍后的模式也可能匹配。
例如,考虑下:
GOVCS=github.com:git,evil.com:off,*:git|hg
使用此设置,具有以github.com/
开头的模块或导入路径的代码只能使用git
; evil.com
上的路径不能使用任何版本控制命令,所有其他路径(*
匹配所有内容)只能使用 git
或 hg
。
特殊模式public
和private
匹配公共和私有模块或导入路径。如果路径与 GOPRIVATE
变量匹配,则该路径是私有的;否则它是公开的。
如果 GOVCS
变量中没有任何规则与特定模块或导入路径匹配,go
命令会应用其默认规则,现在可以用 GOVCS
表示法将其概括为 public:git|hg,private:all
。
要允许对任何包不受限制地使用任何版本控制系统,请使用:
GOVCS=*:all
要禁用所有版本控制,请使用:
GOVCS=*:off
go env -w
命令 可用于设置 GOVCS
变量以供将来调用 go 命令。
GOVCS
是在 Go 1.16 中引入的。 Go 的早期版本可能对任何模块使用任何已知的版本控制工具。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: