管理依赖项

当您的代码使用外部包时,这些包(作为模块分发)成为依赖项。随着时间的推移,您可能需要升级或更换它们。Go 提供了依赖管理工具,可帮助您在合并外部依赖项时确保 Go 应用程序的安全.

本主题介绍如何执行任务以管理您在代码中采用的依赖项。您可以使用 Go 工具执行其中的大部分操作。本主题还介绍了如何执行其他一些您可能会觉得有用的依赖相关任务.

另请参见

使用和管理依赖项的工作流程

您可以通过 Go 工具获取和使用有用的包。在 pkg.go.dev 上,您可以搜索您可能觉得有用的包,然后使用go 命令将这些包导入您自己的代码中以调用它们的函数。

下面列出了最常见的依赖项管理步骤。有关每个选项的详细信息,请参阅本主题中的部分。

  1. pkg.go.dev找到有用的包 .
  2. 在你的代码中 导入所需的包.
  3. 将您的代码添加到模块以进行依赖跟踪(如果它尚未在模块中)。请参阅启用依赖项跟踪
  4. 添加外部包作为依赖项,以便您可以管理它们。
  5. 随着时间的推移,根据需要升级或降级依赖版本

将依赖项作为模块管理

在 Go 中,将依赖项作为包含导入的包的模块进行管理。此过程由以下支持:

定位和导入有用的包

您可以搜索 pkg.go.dev,以查找具有您可能认为有用的函数的包.

找到要在代码中使用的包后,在页面顶部找到包路径,然后单击复制路径按钮将路径复制到剪贴板。在您自己的代码中,将路径粘贴到导入语句中,如下例所示:

import "rsc.io/quote"

在您的代码导入包后,启用依赖项跟踪并获取包的代码进行编译。有关更多信息,请参阅 在代码中启用依赖项跟踪添加依赖项.

在代码中启用依赖项跟踪

要跟踪和管理您添加的依赖项,您首先要将代码放入其自己的模块中。这会在源代码树的根目录创建一个 go.mod 文件。您添加的依赖项将列在该文件中。

要将您的代码添加到它自己的模块中,请使用 go mod init 命令。例如,从命令行切换到代码的根目录,然后按照以下示例运行命令:

$ go mod init example/mymodule

go mod init命令的参数是您的模块的模块路径。如果可能,模块路径应该是源代码的存储库位置

如果一开始您不知道模块的最终存储库位置,请使用安全的替代品。这可能是您拥有的域的名称或您控制的另一个名称(例如您的公司名称),以及来自模块名称或源目录的路径。有关更多信息,请参阅 命名模块

当您使用 Go 工具管理依赖项时,这些工具会更新 go.mod 文件,以便它维护您的依赖项的当前列表。

添加依赖项时,Go 工具还会创建一个 go.sum 文件,其中包含您所依赖的模块的校验和。Go 使用它来验证下载的模块文件的完整性,特别是对于在您的项目上工作的其他开发人员。

在存储库中包含 go.mod 和 go.sum 文件和你的代码。

有关更多信息,请参阅 go.mod 参考.

命名模块

当您运行go mod init创建用于跟踪依赖项的模块时,您指定一个模块路径作为模块的名称。模块路径成为模块中包的导入路径前缀。一定要指定一个不会与其他模块的模块路径冲突的模块路径。

至少,一个模块路径只需要表明它的来源,例如公司或作者或所有者名称。但是路径也可能更能描述模块是什么或做什么。

模块路径通常采用以下形式:

<prefix>/<descriptive-text>

保留的模块路径前缀

Go 保证以下字符串不会在包名称中使用.

添加依赖项

从已发布的模块中导入包后,您可以使用go get 命令 将该模块添加为依赖项进行管理.

该命令执行以下操作:

下面介绍几个例子.

该命令还验证它下载的每个模块。这确保了它从模块发布时起没有变化。如果模块在发布后发生了更改——例如,开发人员更改了提交的内容——Go 工具将出现安全错误。此身份验证检查可保护您免受可能已被篡改的模块的侵害.

获取特定的依赖版本

您可以通过在go get命令中指定依赖模块的版本来获取特定版本的依赖模块。该命令会更新go.mod 文件中的 require指令(尽管您也可以手动更新).

如果出现以下情况,您可能想要这样做:

以下是使用go get 命令的示例:

以下 go.mod 文件 require 指令示例(参见 go.mod 参考了解更多)说明了如何要求特定的版本号:

require example.com/theirmodule v1.3.4

发现可用更新

您可以检查当前模块中的依赖项是否有了新版本。使用go list 命令显示模块的依赖项列表,以及该模块可用的最新版本。一旦你发现了可用的更新,你可以用你的代码尝试它们,来决定是否升级到新版本.

有关go list 命令的更多信息,请参阅go list -m.

这里有几个例子.

升级或降级依赖项

您可以使用 Go 工具发现可用版本,然后添加其他版本作为依赖项,从而升级或降级依赖项模块.

  1. 要发现新版本,请使用 go list 命令,如发现可用更新中所述.

  2. 若要将特定版本添加为依赖项,请使用 go get 命令,如获取特定依赖项版本中所述。

同步代码的依赖项

您可以确保管理所有代码导入包的依赖项,同时删除不再导入的包的依赖项.

当您对代码和依赖项进行更改时,这可能很有用,可能会创建一个已管理依赖项和下载模块的集合,这些依赖项和下载的模块不再与代码中导入的包特别需要的集合匹配.

要保持已管理的依赖集整洁,请使用 go mod tidy 命令。使用您的代码中导入的一组包,此命令编辑您的 go.mod 文件以添加必要但缺少的模块。它还删除了未提供任何相关包的未使用模块。

该命令没有参数,除了一个标志 -v,它打印有关已删除模块的信息。

$ go mod tidy

针对未发布的模块代码进行开发和测试

您可以指定您的代码应使用可能未发布的依赖模块。这些模块的代码可能在它们各自的存储库中,在这些存储库的一个分支(fork)中,或者在具有使用它们的当前模块的驱动器上。

您可能希望在以下情况下执行此操作:

在本地目录中Requiring模块代码

您可以指定所需模块的代码与需要它的代码位于同一本地驱动器上。在以下情况下,您可能会发现这很有用:

若要告诉 Go 命令使用模块代码的本地副本,请使用 go.mod 文件中的 replace 指令替换 require 指令中给定的模块路径.有关指令的更多信息,请参阅 go.mod 参考.

在以下 go.mod 文件示例中,当前模块需要外部模块 example.com/theirmodule,并使用不存在的版本号(v0.0.0-unpublished)来确保替换正常工作。然后,replace 指令将原始模块路径替换为../theirmodule,与当前模块的目录处于同一级别的目录.

module example.com/mymodule

go 1.16

require example.com/theirmodule v0.0.0-unpublished

replace example.com/theirmodule v0.0.0-unpublished => ../theirmodule

设置 require/replace 对时,请使用go mod editgo get命令,以确保文件描述的要求保持一致:

$ go mod edit -replace=example.com/theirmodule@v0.0.0-unpublished=../theirmodule
$ go get -d example.com/theirmodule@v0.0.0-unpublished

注意: 使用 replace 指令时,Go 工具不会对外部模块进行身份验证,如添加依赖项中所述.

有关版本号的更多信息,请参阅模块版本编号.

Requiring来自您自己的存储库fork的外部模块代码

当您对外部模块的存储库进行了 fork (例如修复模块代码中的问题或添加功能)时,您可以让 Go 工具将您的 fork 用于模块的源代码。这对于测试您自己的代码中的更改非常有用。(请注意,您还可以要求将模块代码与需要它的模块一起放在本地驱动器上的目录中。有关详细信息,请参阅在本地目录中Requiring模块代码。)

为此,请在 go.mod 文件中使用 replace 指令将外部模块的原始模块路径替换为你存储库中fork的路径。这会指示 Go 工具在编译时使用替换路径(fork的位置),例如,同时允许您保留import原始模块路径中的语句不变。

有关 replace 指令的详细信息,请参阅 go.mod 文件参考

在下面的 go.mod 文件示例中,当前模块需要外部模块 example.com/theirmodule。然后,replace 指令将原始模块路径替换为 example.com/myfork/theirmodule,这是模块自己的存储库的fork。

module example.com/mymodule

go 1.16

require example.com/theirmodule v1.2.3

replace example.com/theirmodule v1.2.3 => example.com/myfork/theirmodule v1.2.3-fixed

设置require/replace对时,使用 Go 工具命令确保文件描述的需求保持一致。使用 go list 命令获取当前模块正在使用的版本。然后使用go mod edit命令将需要的模块替换为fork:

$ go list -m example.com/theirmodule
example.com/theirmodule v1.2.3
$ go mod edit -replace=example.com/theirmodule@v1.2.3=example.com/myfork/theirmodule@v1.2.3-fixed

注意: 使用 replace 指令时,Go 工具不会对外部模块进行身份验证,如添加依赖项中所述。

有关版本号的更多信息,请参阅模块版本编号 .

使用存储库标识符获取特定提交

您可以使用 go get 命令从模块存储库中的特定提交添加模块的未发布代码。

为此,请使用 go get 命令,使用 @ 符号指定所需的代码。使用 go get 时,该命令将向 go.mod 文件添加一个 require 指令,该指令需要外部模块,使用基于提交详细信息的伪版本号。

以下示例提供了一些说明。它们基于一个模块,其源代码位于 git 存储库中。

删除依赖项

当您的代码不再使用模块中的任何包时,您可以停止将该模块作为依赖项进行跟踪。

要停止跟踪所有未使用的模块,请运行go mod tidy 命令 。此命令还可能添加在模块中构建包所需的缺失依赖项。

$ go mod tidy

要删除特定依赖项,请使用go get 命令,指定模块的模块路径并附加 @none,如下例所示:

$ go get example.com/theirmodule@none

go get 命令还将降级或删除依赖于已删除模块的其他依赖项。

指定模块代理服务器

当您使用 Go 工具处理模块时,这些工具默认从 proxy.golang.org(一个公共的 Google 运行的模块镜像)或直接从模块的存储库下载模块。您可以指定 Go 工具可以使用另一个代理服务器来下载和验证模块。

您可能想要这样做如果您(或您的团队)已经设置或选择了您想要使用不同的模块代理服务器。例如,有些人设置了模块代理服务器,以便更好地控制依赖项的使用方式。

要为 Go 工具指定另一个模块代理服务器,请将 GOPROXY 环境变量设置为一个或多个服务器的 URL。Go 工具将按照您指定的顺序尝试每个 URL。默认情况下,首先 GOPROXY指定一个公共的 Google 运行模块代理,然后从模块的存储库直接下载(在其模块路径中指定):

GOPROXY="https://proxy.golang.org,direct"

有关GOPROXY环境变量的更多信息,包括支持其他行为的值,请参阅go 命令参考

您可以将变量设置为其他模块代理服务器的 URL,用逗号或管道分隔 URL。

Go 模块经常在不是公网上的版本控制服务器和模块代理上开发和分发。您可以设置 GOPRIVATE环境变量。您可以设置GOPRIVATE环境变量来配置go 命令以从私有源下载和构建模块。然后 go 命令可以从私有源下载和构建模块。

GOPRIVATEGONOPROXY 环境变量可以设置为与模块前缀匹配的 glob 模式列表,这些模块前缀是私有的,不应从任何代理请求。例如:

GOPRIVATE=*.corp.example.com,*.research.example.com