本文主要参考文章,个人整理而成。
Go Modules是官方正式推出的包依赖管理项目,在Go Modules推出之前(Go1.13之前)存在两个蛋疼问题:
- 当你使用
go get
命令安装依赖包时,这些包文件总是保存到$GOPATH/src
目录下。Go程序只能导入$GOPATH/src
目录下的依赖包,这种设定强制要求所有的go的项目目录必须在$GOPATH/src
目录下设定导致:如果你的项目在别的目录,那么你将需要频繁切换GOPATH
的值,而整个$GOPATH
目录非常臃肿; - 另一个问题是,由于
go get
总是将这些依赖文件放到相同的目录下(因为目录名与包名相同),导致一个依赖包的多个版本无法共存,这就导致非常容易出现不兼容的问题。而如果你想在别的路径下工作,除了切换GOPATH的值外,所有的依赖需要重新安装。
Go modules 出现的目的之一就是为了解决 GOPATH 的问题,也就相当于是抛弃 GOPATH 了。它有如下特点:
-
以前项目必须在
$GOPATH/src
里进行,现在Go 允许在$GOPATH/src
外的任何目录下使用 go.mod 创建项目。 -
在依赖包版本控制方面,引入了语义化版本的概念,即按照vX.Y.Z的格式定义版本,其中X为主版本,Y为小版本,Z为补丁版本。Go假定当一个依赖包存在不兼容的Breaking changes时,它的主版本将会变化,Go会将不同主版本的依赖包视为不同的module,因此两个不同主版本的依赖包同时存在是非常普遍的。如果是小版本变化(主版本号不变),那这个模块版本肯定就不包含 Breaking changes,这时如果两个依赖包A和B都依赖另一个不同小版本的依赖包C的话,那么就安装最新的依赖包C就行了。
-
当我们希望发布依赖包公用时,你需要提供一个commit hash或者使用一个类似于git tag的方式为这个commit hash添加一个别名。这些Tag必须遵循语义化版本控制,如果没有将忽略 Tag,然后根据你的 Commit 时间和哈希值再为你生成一个假定的符合语义化版本控制的版本号。
-
Global Caching 这个主要是针对 Go modules 的全局缓存数据说明,如下:
- 同一个模块版本的数据只缓存一份,所有其他模块共享使用。
- 目前所有模块版本数据均缓存在
$GOPATH/pkg/mod
和$GOPATH/pkg/sum
下,未来或将移至$GOCACHE/mod
和$GOCACHE/sum
下( 可能会在当$GOPATH
被淘汰后)。 - 可以使用
go clean -modcache
清理所有已缓存的模块版本数据。
-
新增了
go env -w
用于写入环境变量,而写入的地方是os.UserConfigDir
所返回的路径,需要注意的是go env -w
不会覆写系统环境变量,类似于git config的作用。
go.mod文件
go.mod 是启用了 Go moduels 的项目所必须的最重要的文件,它描述了当前项目(也就是当前模块)的元信息,每一行都以一个动词开头,目前有以下 5 个动词:
- module:用于定义当前项目的模块路径。
- go:用于设置预期的 Go 版本。
- require:用于设置一个特定的模块版本。
- exclude:用于从使用中排除一个特定的模块版本。
- // indirect:表名该模组并不是我们程序中直接依赖的,而是直接依赖的包里面导入的依赖;
- replace:用于将一个模块版本替换为另外一个模块版本,比如用local的版本替代remote的版本。
go.sum文件
go.sum
类似于npm
中的package-lock.json
这类文件,它详细罗列了当前项目直接或间接依赖的所有模块版本,并写明了那些模块版本的 SHA-256 哈希值以备 Go在今后的操作中保证项目所依赖的那些模块版本不会被篡改。但是必须注意的是,不同于其他语言,go.sum文件更新应该包含在你的提交中,以确保你的依赖模块可以100%被重新构建。
GOPROXY配置
这个环境变量主要是用于设置 Go 模块代理,它的值是一个以英文逗号 “,” 分割的 Go module proxy 列表,默认是proxy.golang.org,国内访问不了。这里要感谢盛傲飞和七牛云为中国乃至全世界的 Go 语言开发者提供免费、可靠的、持续在线的且经过CDN加速Go module proxy(goproxy.cn)。
其实值列表中的 “direct” 为特殊指示符,用于指示 Go 回源到模块版本的源地址去抓取(比如 GitHub 等),当值列表中上一个 Go module proxy 返回 404 或 410 错误时,Go 自动尝试列表中的下一个,遇见 “direct” 时回源,遇见 EOF 时终止并抛出类似 “invalid version: unknown revision...” 的错误。
国内推荐配置为:
export GOPROXY="https://goproxy.cn, direct"
# 或者
go env -w GOPROXY=https://goproxy.cn,direct
Vendor目录
有时由于一些网络原因我们可能无法下载我们需要的依赖,这时我们需要提前准备这些依赖。我们可以通过go mod vendor
命令输出我们所有的依赖到对应的 vendor
目录(位于我们自己的模组目录下),然后通过运行go build -mod vendor
命令来强制使用vendor
目录的依赖。
命令汇总
# 查看所有 go mod的使用命令
go mod
# module为项目目录名,生成 go.mod 文件
go mod init [module-name]
# 更新现有依赖
go mod tidy
# 下载 go.mod 文件中指明的所有依赖
go mod download
# 查看项目所有依赖
go list -m all
# 查看现有的依赖结构
go mod graph
# 编辑 go.mod 文件
go mod edit
# 导出现有的所有依赖 (事实上 Go modules 正在淡化 Vendor 的概念)
go mod vendor
# 校验一个模块是否被篡改过
go mod verify
# 清理所有已缓存的模块版本数据。
go clean -modcache
# 更新主要模块,但是忽略单元测试
go get -u
# 更新所有模块,推荐使用
go get -u all
网友评论