管理依赖项

当您的代码使用外部包时,这些包(以模块形式分发)就变成了依赖项。随着时间的推移,您可能需要升级或替换它们。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)或与使用它们的当前模块位于同一驱动器上。

您可能希望在以下情况下这样做:

需要本地目录中的模块代码

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

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

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

module example.com/mymodule

go 1.23.0

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 example.com/theirmodule@v0.0.0-unpublished

注意:当您使用 replace 指令时,Go 工具不会像 添加依赖项 中描述的那样验证外部模块。

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

需要您自己的仓库派生(fork)中的外部模块代码

当您派生(fork)了外部模块的仓库(例如为了修复模块代码中的问题或添加功能)后,您可以让 Go 工具使用您的派生(fork)作为模块的源。这对于从您自己的代码中测试更改非常有用。(请注意,您也可以在与需要它的模块位于同一本地驱动器上的目录中需要该模块代码。更多信息请参阅 需要本地目录中的模块代码。)

您可以通过在 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.23.0

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 编写并在处理模块时使用的开发者工具。例如,您可能会将 stringergo generate 一起使用,或者使用特定的 linter 或 formatter 作为准备提交更改的一部分。

在 Go 1.24 及更高版本中,您可以使用以下命令添加工具依赖项:

$ go get -tool golang.org/x/tools/cmd/stringer

这会将 tool 指令 添加到您的 go.mod 文件中,并确保存在必要的 require 指令。添加此指令后,您可以通过将工具导入路径的最后一个 非主版本 组件传递给 go tool 来运行该工具:

$ go tool stringer

如果多个工具共享最后一个路径片段,或者路径片段与 Go 分发版附带的工具之一匹配,则必须传递完整的包路径:

$ go tool golang.org/x/tools/cmd/stringer

要查看当前所有可用工具的列表,请不带任何参数运行 go tool

$ go tool

您可以手动将 tool 指令添加到您的 go.mod 中,但必须确保存在定义该工具的模块的 require 指令。添加任何缺失的 require 指令的最简单方法是运行:

$ go mod tidy

满足工具依赖项所需的依赖项行为与您 模块图 中的任何其他依赖项一样。它们参与 最小版本选择 并遵守 requirereplaceexclude 指令。由于模块修剪,当您依赖一个本身具有工具依赖项的模块时,仅为满足该工具依赖项而存在的依赖项通常不会成为您模块的依赖项。

tool 元模式 提供了一种同时对所有工具执行操作的方法。例如,您可以使用 go get -u tool 升级所有工具,或者使用 go install tool 将它们全部安装到 $GOBIN。

在 Go 1.24 之前的版本中,您可以通过在模块内的 Go 文件中添加一个空导入来实现类似于 tool 指令的功能,该文件使用 构建约束 从构建中排除。如果这样做,您就可以使用带完整包路径的 go run 来运行该工具。

指定模块代理服务器

当您使用 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 环境变量来配置 go 命令从私有源下载和构建模块。然后 go 命令就可以从私有源下载和构建模块。

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

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