Skip to content

Instantly share code, notes, and snippets.

@Akagi201
Created December 17, 2018 02:27
Show Gist options
  • Save Akagi201/3380fbb54a89ebc227e27ec000cba816 to your computer and use it in GitHub Desktop.
Save Akagi201/3380fbb54a89ebc227e27ec000cba816 to your computer and use it in GitHub Desktop.
[go-mod]

go mod 项目管理

go 1.11 有了对模块的实验性支持,大部分的子命令都知道如何处理一个模块,比如 run build install get list mod 子命令,第三方工具可能会支持的晚一些。

到 go 1.12 会删除对 GOPATH 的支持,go get 命令也会变成只能获取模块,不能像现在这样直接获取一个裸包。

可以用环境变量 GO111MODULE 开启或关闭模块支持,它有三个可选值:off、on、auto,默认值是 auto。

开启go mod机制

请选择go1.11以上版本

GO111MODULE=off 无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包。

GO111MODULE=on 模块支持,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖。

GO111MODULE=auto 在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持。

在使用模块的时候,GOPATH 是无意义的,不过它还是会把下载的依赖储存在 $GOPATH/pkg/mod 中,也会把 go install 的结果放在 $GOPATH/bin 中。

模块根目录和其子目录的所有包构成模块,在根目录下存在 go.mod 文件,子目录会向着父目录、爷目录一直找到 go.mod 文件。

模块路径指模块根目录的导入路径,也是其他子目录导入路径的前缀。go.mod 文件第一行定义了模块路径,有了这一行才算作是一个模块。

go.mod 文件接下来的篇幅用来定义当前模块的依赖和依赖版本,也可以排除依赖和替换依赖。

module example.com/m 

require (
    golang.org/x/text v0.3.0 
    gopkg.in/yaml.v2 v2.1.0 
)

replace (
    golang.org/x/text => github.com/golang/text v0.3.0 
)

这个文件不用手写,可以用 go mod init example.com/m 生成 go.mod 的第一行,文件的剩余部分也不用担心,执行 go mod tidy 命令会根据需要的依赖自动生成 require 语句。

官方建议经常维护这个文件,保持依赖项是干净的。对于国内用户来说,手动维护这个文件是必然的,因为你需要把 golang.org/x/text 替换成 github.com/golang/text 啊。

不需要像以前那样以 hack 的方式替换 GOPATH 中的依赖,去替换模块的下载缓存,不过如果用 GOPROXY 功能也确实可以做到替换。

定义模块

go mod init:命令�初始化一个package,生成go.md�文件。例如:

module git.5th.im/core-team/shiralee-node

生成版本依赖

go get、�build、fmt:�命令对源码进行语义分析,生成依赖版本内容:go.mod,以及版本指纹文件:go.sum

module git.5th.im/core-team/shiralee-node

require (
	git.5th.im/core-team/rpc-protos v0.0.0-20181214105841-807dc8546b17
	gopkg.in/urfave/cli.v1 v1.20.0
	gopkg.in/yaml.v2 v2.2.2
    ...
)

�锁定依赖版本

go build等命令运行时�,默认使用的依赖版本都是最新的依赖,有时我们需要锁定依赖package版本号,运行如下命令,就会修改go.mod、go.sum文件。例如

go get git.5th.im/core-team/exchange-shiralee@分支名 
go get git.5th.im/core-team/exchange-shiralee@版本号
go get git.5th.im/core-team/exchange-shiralee@commit hash

替换指定git remote路径

module git.5th.im/core-team/shiralee-node

require (
    git.5th.im/core-team/shiralee v0.0.0 //注意添加这个
	git.5th.im/core-team/rpc-protos v0.0.0-20181214105841-807dc8546b17
	git.5th.im/core-team/swissgear v0.0.0-20181214085106-b2b08cbb8ba4
	gopkg.in/gavv/httpexpect.v1 v1.0.0-20180803094507-bdde30871313 // indirect
	gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce
	gopkg.in/urfave/cli.v1 v1.20.0
	gopkg.in/yaml.v2 v2.2.2
    ...
)

replace git.5th.im/core-team/shiralee => git.5th.im/core-team/exchange-shiralee v0.0.0-20181214110005-8db892ab39e5 //替换指定的文件

命令介绍

go list 命令

go list -m 可以查看当前的依赖和版本

go mod 命令

这个子命令用来处理 go.mod 文件,上一小节我们已经见过 go mod init 和 go mod tidy 了。

go mod edit -fmt 格式化 go.mod 文件。

go mod edit -require=path@version 添加依赖或修改依赖版本,这里支持模糊匹配版本号,详情可以看下文 go get 的用法。

go mod tidy 从 go.mod 删除不需要的依赖、新增需要的依赖,这个操作不会改变依赖版本。

go mod vendor 生成 vendor 文件夹。

其他的自行 go help mod 查看。

go get 命令

获取依赖的特定版本,用来升级和降级依赖。可以自动修改 go.mod 文件,而且依赖的依赖版本号也可能会变。在 go.mod 中使用 exclude 排除的包,不能 go get 下来。

与以前不同的是,新版 go get 可以在末尾加 @ 符号,用来指定版本。

它要求仓库必须用 v1.2.0 格式打 tag,像 v1.2 少个零都不行的,必须是语义化的、带 v 前缀的版本号。

go get github.com/gorilla/mux    # 匹配最新的一个 tag
go get github.com/gorilla/mux@latest    # 和上面一样
go get github.com/gorilla/[email protected]    # 匹配 v1.6.2
go get github.com/gorilla/mux@e3702bed2 # 匹配 v1.6.2
go get github.com/gorilla/mux@c856192   # 匹配 c85619274f5d
go get github.com/gorilla/mux@master    # 匹配 master 分支

latest 匹配最新的 tag。

v1.2.6 完整版本的写法。

v1、v1.2 匹配带这个前缀的最新版本,如果最新版是 1.2.7,它们会匹配 1.2.7。

c856192 版本 hash 前缀、分支名、无语义化的标签,在 go.mod 里都会会使用约定写法 v0.0.0-20180517173623-c85619274f5d,也被称作伪版本。

go get 可以模糊匹配版本号,但 go.mod 文件只体现完整的版本号,即 v1.2.0、v0.0.0-20180517173623-c85619274f5d,只不过不需要手写这么长的版本号,

用 go get 或上文的 go mod edit -require 模糊匹配即可,它会把匹配到的完整版本号写进 go.mod 文件。

go build 命令

go build -mod=readonly 防止隐式修改 go.mod,如果遇到有隐式修改的情况会报错,可以用来测试 go.mod 中的依赖是否整洁,但如果明确调用了 go mod、go get 命令则依然会导致 go.mod 文件被修改。

go build -mod=vendor 在开启模块支持的情况下,用这个可以退回到使用 vendor 的时代。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment