go包管理
1. 三种包管理方式
使用go path问题
- 代码开发必须在go path src目录下,不然,就有问题。
- 依赖手动管理
- 依赖包没有版本可言
从这个看, go path不算包管理工具
govendor
- 解决了包依赖,一个配置文件就管理
- 依赖包全都下载到项目vendor下,每个项目都把有一份。拉取项目时,开始怀疑人生。
go mod介绍
go modules 是 golang 1.11 新加的特性。现在1.12 已经发布了,是时候用起来了。Modules官方定义为:
模块是相关Go包的集合。modules是源代码交换和版本控制的单元。 go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。
2. go mod基本说明
下面设置go mod和go proxy
1 |
|
GO111MODULE
GO111MODULE 有三个值:off, on和auto(默认值)。
GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。
GO111MODULE=on,go命令行会使用modules,而一点也不会去GOPATH目录下查找。
GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:
1 |
|
当modules功能启用时,依赖包的存放位置变更为$GOPATH/pkg,允许同一个package多个版本并存,且多个项目可以共享缓存的 module
3. go mod命令
命令 | 说明 |
---|---|
download |
下载依赖包到本地缓存 |
edit |
从工具或脚本编辑 go.mod 文件 |
graph |
打印模块依赖图 |
init |
在当前目录初始化新模块 |
tidy |
拉取缺少的模块,移除不用的模块 |
vendor |
将依赖复制到 vendor 目录下 |
verify |
验证依赖是否正确 |
why |
解释为什么需要某些包或模块 |
初始化项目
在项目根目录下执行go mod init xxx
,go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。
go.mod 提供了module, require、replace和exclude 四个命令
module
语句指定包的名字(路径)require
语句指定的依赖项模块replace
语句可以替换依赖项模块exclude
语句可以忽略依赖项模块
添加依赖
在使用Go模块(Go Modules)管理依赖时,Go工具链遵循一定的原则来决定应该安装哪个版本的包(package)。下面是这些原则的详细解释:
- 安装包的原则
当你使用go get
命令来安装一个包时,Go会首先检查该包的所有公开发布的版本(通常是通过git标签来标记的版本)。Go的偏好是:
-
首先拉取最新的发布版本(release tag):这意味着如果一个库有一个或多个发布的版本,Go将会选择最新的版本。这些版本通常会遵循语义版本控制(SemVer),比如
v1.2.3
。 -
如果没有发布的版本,将拉取最新的commit:如果一个库没有任何发布的版本标签,Go将会使用该库的最新commit。这种情况下,依赖的版本可能不稳定,因为它直接反映了库在主分支(通常是
master
或main
)上的最新开发状态。
这种机制旨在确保项目能够利用依赖的稳定和经过测试的版本,同时也提供了一种方法来使用最新或未发布的更改。
go.sum
文件
当你使用Go模块工作时,Go工具会自动创建和维护一个名为go.sum
的文件。这个文件的作用包括:
-
记录依赖树(dependency tree):
go.sum
文件包含了项目所依赖的每个模块的精确版本和这些版本的哈希值。这不仅仅是直接依赖,还包括这些依赖所依赖的其他模块(即间接依赖)。 -
确保依赖的完整性和安全性:通过记录每个依赖版本的哈希值,
go.sum
文件帮助确保这些依赖在将来获取时仍然是一致的,未被篡改。这意味着无论何时何地构建项目,所使用的依赖都应该是完全相同的,从而提高了构建的可重复性和安全性。
go get升级
- 运行
go get -u
将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号) - 运行
go get -u=patch
将会升级到最新的修订版本 - 运行
go get package@version
将会升级到指定的版本号version - 运行go get如果有版本的更改,那么go.mod文件也会更改
使用replace替换无法直接获取的package
由于某些已知的原因,并不是所有的package都能成功下载,比如:golang.org下的包。
modules 可以通过在 go.mod 文件中使用 replace 指令替换成github上对应的库,比如:
1 |
|
为什么使用 replace
?
- 处理无法访问的包:有些包,比如
golang.org/x/
下的包,在某些地区可能无法直接访问或下载。虽然这些包通常也在GitHub上有镜像,但Go工具链默认可能直接尝试从原始的golang.org
域名下载,导致失败。使用replace
指令可以将这些包的来源重定向到GitHub上的镜像地址,确保下载和使用的可行性。 - 开发和调试:如果你正在开发或修改某个依赖库,并希望在项目中测试它,你可以使用
replace
将依赖指向你本地的文件路径,而不是远程库。这样可以即时看到本地更改的效果,而无需推送更改到远程仓库。 - 依赖问题修复:有时候,一个库的特定版本可能包含错误或问题,而这些问题在另一个版本或fork中已经被修复。通过
replace
,你可以强制项目使用修复后的版本。
4. go mod发布和使用
Creating a Module
如果你设置好go mod了,那你就可以在任何目录下随便创建
1 |
|
在这个目录下创建一个文件say.go
1 |
|
初始化一个 go.mod
文件
1 |
|
查看 go.mod内容如下:
1 |
|
下面我们要将这个module发布到github上,然后在另外一个程序使用
1 |
|
执行完,上面我们就相当于发布完了。
如果有人需要使用,就可以使用
1 |
|
这个时候没有加tag,所以,没有版本的控制。默认是v0.0.0后面接上时间和commitid。如下:
1 |
|
官方不建议这样做,没有进行版本控制管理。
module versioning
使用tag,进行版本控制
making a release:
1 |
|
操作完,我们的module就发布了一个v1.0.0的版本了。
推荐在这个状态下,再切出一个分支,用于后续v1.0.0的修复推送,不要直接在master分支修复
1 |
|
5. Vendoring
Vendoring 概述
Vendoring允许你将所有的外部依赖复制到你的项目内部(通常是vendor
目录)。这样做的主要好处是确保构建的可重复性,无论外部源的状态如何变化,你的项目都可以使用已经存储的、不变的依赖版本进行构建。
使用vendor
目录的好处
- 离线构建:在
vendor
目录中保留所有依赖的副本,可以在没有网络连接的情况下构建项目。 - 控制和稳定性:锁定依赖的具体版本,防止未经意的升级引入潜在的问题。
- 避免依赖消失:如果一个依赖库从公共存储库中消失,拥有本地副本意味着你的项目仍然可以构建和运行。
- 合规和审核:对于需要严格审计依赖来源和版本的环境,vendor目录提供了一个简单的解决方案。
如何使用vendor
目录
- 生成
vendor
目录
虽然go mod vendor
是正确的命令,但你提供的命令有误。正确的命令是:
1 |
|
这个命令会根据项目根目录下的go.mod
文件,将所有依赖复制到vendor
目录中。执行后,所有的模块依赖都会按照go.mod
文件中记录的具体版本,存放在项目的vendor
目录中。
- 构建时使用
vendor
目录
当你希望Go工具链在构建项目时使用vendor
目录中的依赖,而不是下载最新的或缓存的依赖,可以使用如下命令:
1 |
|
这个命令告诉Go编译器在构建时查找vendor
目录中的依赖。这是确保项目使用已验证和已审计依赖的一种方式,特别是在生产环境中部署时。
- 类似的
1 |
|