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 #