这是我参与「第五届青训营 」伴学笔记创作活动的第3天,详细了解了go依赖管理的发展路程 包的依赖管理经历了三个阶段:GOPATH、Go Vendor、Go Module
GOPATH
gopath可以理解为工作目录,这个目录下有如下目录结构
bin:存放编译后生成的二进制可执行文件 pkg:存放编译后生成的 .a 文件 src:存放项目的源代码,可以是你自己写的代码,也可以是你 go get 下载的包 将你的包或者别人的包全部放在 $GOPATH/src 目录下进行管理的方式,我们称之为 GOPATH 模式。
在GOPATH中,没有版本的概念
你无法在你的项目中,使用指定版本的包,因为不同版本的包的导入方法也都一样 其他人运行你的开发的程序时,无法保证他下载的包版本是你所期望的版本,当对方使用了其他版本,有可能导致程序无法正常运行 在本地,一个包只能保留一个版本,意味着你在本地开发的所有项目,都得用同一个版本的包,这几乎是不可能的。
go vendor
解决了GOPATAH无法使用多版本库的问题,解决的办法是:在每个项目下都创建一个vendor目录,每个项目所需的依赖都只会下载到自己vendor目录下,项目之间依赖的包互不影响
搜索依赖包的优先级如下
- 当前包下的vendor目录
- 向上级目录查找,直到src下的vendor目录
- 在GOROOT目录下查找
- 在GOPATH下面查找依赖包
缺点:
- 无法对第三方包的集中式管理。当多个项目用到同一个包的同一个版本时,该包会存在于该机器上的不同目录下(即不同vendor下),浪费了磁盘空间
- 当想要开源项目时需要把项目+所有依赖的包一并传上去,而且别人也需要把依赖的包在拷贝项目代码时也一起下载,这样子才能保证项目正常运行
Go Module
启用go mod之后(把GO111MODULE设置成on),可以脱离GOPATH来创建项目。go mod会将所有的依赖包安装在$GOPATH/pkg目录下
go.mod
-
第一行:模块的引用路径,即引用项目中其他包时的根路径,如图:
-
第二行:项目使用go的版本
-
第三行:项目所需的直接依赖包及其版本
在go.mod中会出现两个flag
exclude:忽略指定版本的依赖包
replace:由于在国内访问golang.org/x的各个包都需要f.g,因此可以在go.mod中使用replace替换成github上对应的库
go.sum
每一行都是由模块路径,模块版本,哈希检验值组成,其中哈希检验值是保证当前缓存的模块不会被篡改。hash是以h1:开头的字符串,表示生成的checksum(校验和)的算法是第一版的hash算法(sha256)
有的包只有一行
<module> <version>/go.mod <hash>
而有的包有两行
<module> <version> <hash>
<module> <version>/go.mod <hash>
有两行的包,区别就在于hash值不一样,一个是h1:hash,一个是go.mod h1:hash
h1:hash和go.mod h1:hash两者,要不同时存在,要不只存在go.mod h1:hash。不存在h1:hash的情况是Go认为肯定用不到某个模块版本的时候就会省略h1:hash
注意
go.mod和go.sum是go modules版本管理的指导性文件,因此go.mod和go.sum文件都应该提交到Git仓库中,避免其他人使用项目时,重新生成的go.mod和go.sum与你开发的基准版本不一致
go mod命令使用
- go mod init:初始化go mod, 生成go.mod文件,后可接参数指定 module 名,上面已经演示过。
- go mod download:手动触发下载依赖包到本地cache(默认为$GOPATH/pkg/mod目录)
- go mod graph: 打印项目的模块依赖结构
- go mod tidy :添加缺少的包,且删除无用的包
- go mod verify :校验模块是否被篡改过
- go mod why: 查看为什么需要依赖
- go mod vendor :导出项目所有依赖到vendor下
- go mod edit :编辑go.mod文件,接-fmt参数格式化 go.mod 文件,接-require=golang.org/x/text添加依赖,接-droprequire=golang.org/x/text 删除依赖,详情可参考 go help mod edit
- go list -m -json all:以 json 的方式打印依赖详情