go module
基本概念介绍 go 1.11+ 支持
go 1.13+ 默认
Introduction to Go Modules – Roberto Selbach
环境变量
GO111MODULE
设置
要使用go module
,首先要设置GO111MODULE=on
go env -w GO111MODULE=on
启或关闭模块支持
GO111MODULE=off禁用模块支持
编译时会从 GOPATH 和 vendor 文件夹中查找包。
GO111MODULE=on启用模块支持
编译时会忽略GOPATH和vendor文件夹
只根据 go.mod下载依赖
将依赖下载至 %GOPATH%/pkg/mod/ 目录下
GO111MODULE=auto
当项目在 $GOPATH/src外且项目根目录有go.mod文件时 开启模块支持
设置GO111MODULE=on
之后就可以使用go module
了,以后就没有必要在GOPATH
中创建项目了
能够很好的管理项目依赖的第三方包信息
使用 go module
管理依赖后会在项目根目录下生成两个文件go.mod
和go.sum
代理
GOPROXY
Go1.13
之后GOPROXY
默认值为https://proxy.golang.org
(国内无法访问)
设置代理
go env -w GOPROXY=https://goproxy.cn,direct
GO mod
命令
常用命令
go mod download 下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit 编辑go.mod文件
go mod graph 打印模块依赖图
go mod init 初始化当前文件夹, 创建go.mod文件
go mod tidy 增加缺少的module,删除无用的module
go mod vendor 将依赖复制到vendor下
go mod verify 校验依赖
go mod why 解释为什么需要依赖
go.mod
文件结构
项目所有的依赖信息
// 包名
module github.com/xxx
go 1.12
// 依赖包及版本
require (
github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586
github.com/gin-gonic/gin v1.4.0
github.com/go-sql-driver/mysql v1.4.1
github.com/jmoiron/sqlx v1.2.0
github.com/satori/go.uuid v1.2.0
google.golang.org/appengine v1.6.1 // indirect 表示间接引用
)
go mod支持语义化版本号
,比如go get foo@v1.2.3
也可以跟git的分支或tag,比如go get foo@master
当然也可以跟git提交哈希,比如go get foo@e3702bed2
-
replace
替换github
=>golang.org
(需要翻墙访问)replace ( golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac golang.org/x/net v0.0.0-20180821023952-922f4815f713 => github.com/golang/net v0.0.0-20180826012351-8a410e7b638d golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0 )
go mod vendor
go mod vendor 会复制modules下载到vendor中
貌似只会下载你代码中引用的库,而不是go.mod中定义全部的module。
go get
下载依赖包(指定版本)
go get -u 升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
go get -u=patch 升级到最新的修订版本
go get package@version 升级到指定的版本号version
下载所有依赖可以使用 go mod download
命令
go mod tidy
重新整理依赖
删除依赖代码后,相关的依赖库并不会在go.mod文件中自动移除
这种情况下可以使用go mod tidy命令更新go.mod中的依赖关系
go mod edit
修改go.mod文件
go mod edit -fmt 格式化
go mod edit -require=golang.org/x/text 添加依赖项
go mod edit -droprequire=golang.org/x/text 移除依赖项
使用
go mod
已有项目
在 项目目录下 执行 go mod init,生成一个go.mod文件
例: $GOPATH/github.com/smallnest/rpcx
1) go mod init github.com/smallnest/rpcx
2) go get ./... (查找依赖,并记录在go.mod) (指定 -tags,这样可以把tags的依赖都查找到)
3) go mod tidy也可以用来为go.mod增加丢失的依赖
执行上面的命令会把go.mod的latest版本换成实际的最新的版本,并且会生成一个go.sum记录每个依赖库的版本和哈希值
新项目
在GOPATH之外创建新的项目
1) go mod init packagename可以创建一个空的go.mod
2) 可以在其中增加require github.com/smallnest/rpcx latest依赖,或者像上面一样让go自动发现和维护
3) go mod download可以下载所需要的依赖,但是依赖并不是下载到$GOPATH中,而是$GOPATH/pkg/mod中,多个项目可以共享缓存的module
go mod
基本使用
创建一个module
注意: 此目录应位于
$GOPATH
之外,因为默认情况下,$GOPATH
中的模块支持已禁用
this directory should be outside your $GOPATH because by default,
the modules support is disabled inside it
1) 创建module
mkdir testmod
cd testmod
package testmod
import "fmt"
// Hi returns a friendly greeting
func Hi(name string) string {
return fmt.Sprintf("Hi, %s", name)
}
2) 增加go.mod
文件
go mod init github.com/username/testmod
# go: creating new go.mod: module github.com/username/testmod
go.mod
module github.com/username/gomodtest
go 1.12
3) 上传模块到github
$ git init
$ git add *
$ git commit -am "First commit"
# github新建仓库 testmod
$ git remote add origin https://github.com/username/testmod.git
$ git push -u origin master
4) go get
获取模块
go get github.com/username/testmod
注意: 直接
go get <module>
获取的是master
的模块 (我们需要制定版本)
模块的版本
Go模块是版本化的,并且某些版本具有某些特殊性
-
语义版本控制
X.Y.Z
语义化版本版本格式:主版本号.次版本号.修订号,版本号递增规则如下: 主版本号:当你做了不兼容的 API 修改, 次版本号:当你做了向下兼容的功能性新增, 修订号:当你做了向下兼容的问题修正。 先行版本号及版本编译元数据可以加到“主版本号.次版本号.修订号”的后面,作为延伸
更重要的是,Go在查找版本时会使用仓库标签tag
,而某些版本则与其他版本有所不同
例如 版本2和更高版本的导入路径应与版本0和版本1不同(我们将介绍该路径)
此外,默认情况下,Go会获取存储库中可用的最新标记版本 tag
。
这是一个重要的陷阱,因为您可能习惯于使用master分支。
要发布我们的软件包,我们需要使用版本tag
标记我们的仓库
制作第一个 release 版本
# 在Github仓库上创建了一个标记,将当前提交标记为1.0.0版
git tag v1.0.0
git push --tags
创建一个新分支 v1
git checkout -b v1
git push -u origin v1
使用模块
1) 新建 go module
(pycharm file->new->project->go module
) 注意 proxy: direct 需要删除
2) 新建 main.go
package main
import (
"fmt"
"github.com/landybird/testmod"
)
func main() {
fmt.Println(testmod.Hi("roberto"))
}
3) mod 初始化
go mod init mod
go build
修改模块版本
修改testmod模块代码
// Hi returns a friendly greeting
func Hi(name string) string {
- return fmt.Sprintf("Hi, %s", name)
+ return fmt.Sprintf("Hi, %s!", name)
}
版本升级
git commit -m "Emphasize our friendliness" testmod.go
git tag v1.0.1
git push --tags origin v1
go get
下载依赖包(指定版本)
go get -u 升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
原来1.0.0 1.0.1 或者 1.1.0
go get -u=patch 升级到最新的修订版本
1.0.1 而不是 1.1.0
go get package@version 升级到指定的版本号version
github.com/landybird/testmod@v1.0.1
主版本号 Major versions
升级
主要版本可能会破坏向后兼容性
从Go模块的角度来看,主要版本是完全不同的软件包
修改 testmod.go
package testmod
import (
"errors"
"fmt"
)
// Hi returns a friendly greeting in language lang
func Hi(name, lang string) (string, error) {
switch lang {
case "en":
return fmt.Sprintf("Hi, %s!", name), nil
case "pt":
return fmt.Sprintf("Oi, %s!", name), nil
case "es":
return fmt.Sprintf("¡Hola, %s!", name), nil
case "fr":
return fmt.Sprintf("Bonjour, %s!", name), nil
default:
return "", errors.New("unknown language")
}
}
修改go.mod
更改导入路径
module github.com/landybird/testmod => module github.com/landybird/testmod/v2
可以认为 已经是不同的module了
新建 v2 分支, 升级版本
git commit testmod.go -m "Change Hi to allow multilang"
git checkout -b v2 # optional but recommended
echo "module github.com/landybird/testmod/v2" > go.mod # 修改moudle路径
git commit go.mod -m "Bump version to v2"
git tag v2.0.0
git push --tags origin v2 # or master if we don't have a branch
运行 go build
获取最新的版本包
代码中导入新的包
package main
import (
"fmt"
"github.com/landybird/testmod"
testmodML "github.com/landybird/testmod/v2" // 路径以“ v2”结尾,Go仍将使用其专有名称(“ testmod”)来引用模块
)
func main() {
fmt.Println(testmod.Hi("roberto"))
g, err := testmodML.Hi("jimmy", "cn")
if err != nil {
panic(err)
}
fmt.Println(g)
}
go mod tidy
升级之后go.mod
中
module mod
go 1.15
require github.com/landybird/testmod v1.0.1
require github.com/robteix/testmod/v2 v2.0.0
这时候如果代码中 只引用 github.com/landybird/testmod
去掉 github.com/landybird/testmod/v2
需要重新生成 go.mod
的依赖路径
go mod tidy # 调整路径
module mod
go 1.15
require github.com/landybird/testmod v1.0.1
支持vendors
Go模块默认情况下会忽略vendor/目录
但是,如果我们仍然想将vendored dependencies
添加到我们的版本控制中,我们仍然可以这样做:
go mod vendor # 这将在项目的根目录下创建一个 vendor/目录,其中包含所有依赖项的源代码
go build -mod vendor #