go mod
————
————
Usage:
go mod <command> [arguments]
命令 | 说明 |
---|---|
download | download modules to local cache(下载依赖包) |
edit | edit go.mod from tools or scripts(编辑go.mod) |
graph | print module requirement graph (打印模块依赖图) |
verify | initialize new module in current directory(在当前目录初始化mod) |
tidy | add missing and remove unused modules(拉取缺少的模块,移除不用的模块) |
vendor | make vendored copy of dependencies(将依赖复制到vendor下) |
verify | verify dependencies have expected content (验证依赖是否正确) |
why | explain why packages or modules are needed(解释为什么需要依赖) |
使用go mod管理一个新项目
初始化项目
D:\study\go_study\example01>go mod init example01
go: creating new go.mod: module example01
go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。
查看go.mod
module example01
go 1.15
go.mod 提供了module, require、replace和exclude 四个命令
module
语句指定包的名字(路径)require
语句指定的依赖项模块replace
语句可以替换依赖项模块exclude
语句可以忽略依赖项模块
添加依赖
创建main.go 文件
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
执行 go run main.go 运行代码会发现 go mod 会自动查找依赖自动下载
- 问题一:依赖的包下载到哪里了?还在GOPATH/src里吗?
不在。
使用Go的包管理方式,依赖的第三方包被下载到了$GOPATH/pkg/mod
路径下。
再查看 go.mod
module example01
go 1.15
require github.com/gin-gonic/gin v1.6.3
go module 安装 package 的原則是先拉最新的 release tag,若无tag则拉最新的commit
go 会自动生成一个 go.sum 文件来记录 dependency tree
![img](https:upload-images.jianshu.io/upload_images/1293367-6d16a0d961653490.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)
再次执行脚本 go run main.go发现跳过了检查并安装依赖的步骤。
可以使用命令 go list -m -u all 来检查可以升级的package,使用go get -u need-upgrade-package 升级后会将新的依赖版本更新到go.mod * 也可以使用 go get -u 升级所有依赖
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上对应的库,比如:
replace (
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
)
go mod发布和使用
creating a module
如果你设置好go mod了,那你就可以在任何目录下随便创建
$mkdir gomodone
$cd gomodone
在这个目录下创建一个文件say.go
package gomodone
import "fmt"
// say Hi to someone
func SayHi(name string) string {
return fmt.Sprintf("Hi, %s", name)
}
初始化一个 go.mod
文件
$ go mod init github.com/jacksonyoudi/gomodone
go: creating new go.mod: module github.com/jacksonyoudi/gomodone
查看 go.mod内容如下:
github.com/jacksonyoudi/gomodone
go 1.14
下面我们要将这个module发布到github上,然后在另外一个程序使用
$git init
$vim .gitiiignore
$git commit -am "init"
// github创建对应的repo
$git remote add origin git@github.com:jacksonyoudi/gomodone.git
$git push -u origin master
执行完,上面我们就相当于发布完了。
如果有人需要使用,就可以使用
go get github.com/jacksonyoudi/gomodone
这个时候没有加tag,所以,没有版本的控制。默认是v0.0.0后面接上时间和commitid。如下:
gomodone@v0.0.0-20200517004046-ee882713fd1e
module versioning
使用tag,进行版本控制
making a release
git tag v1.0.0
git push --tags
操作完,我们的module就发布了一个v1.0.0的版本了。
推荐在这个状态下,再切出一个分支,用于后续v1.0.0的修复推送,不要直接在master分支修复
$git checkout -b v1
$git push -u origin v1
use our module
上面已经发布了一个v1.0.0的版本,我们可以在另一个项目中使用,创建一个go的项目
$mkdir Gone
$cd Gone
$vim main.go
package main
import (
"fmt"
"github.com/jacksonyoudi/gomodone"
)
func main() {
fmt.Println(gomodone.SayHi("Roberto"))
}
代码写好了,我们生成 go mod文件
go mod init Gone
上面命令执行完,会生成 go mod文件
看下mod文件:
module Gone
go 1.14
require (
github.com/jacksonyoudi/gomodone v1.0.0
)
$go mod tidy
go: finding module for package github.com/jacksonyoudi/gomodone
go: found github.com/jacksonyoudi/gomodone in github.com/jacksonyoudi/gomodone v1.0.0
同时还生成了go.sum, 其中包含软件包的哈希值,以确保我们具有正确的版本和文件。
github.com/jacksonyoudi/gomodone v1.0.1 h1:jFd+qZlAB0R3zqrC9kwO8IgPrAdayMUS0rSHMDc/uG8=
github.com/jacksonyoudi/gomodone v1.0.1/go.mod h1:XWi+BLbuiuC2YM8Qz4yQzTSPtHt3T3hrlNN2pNlyA94=
github.com/jacksonyoudi/gomodone/v2 v2.0.0 h1:GpzGeXCx/Xv2ueiZJ8hEhFwLu7xjxLBjkOYSmg8Ya/w=
github.com/jacksonyoudi/gomodone/v2 v2.0.0/go.mod h1:L8uFPSZNHoAhpaePWUfKmGinjufYdw9c2i70xtBorSw=
这个内容是下面的,需要操作执行的结果
go run main.go就可以运行了
Making a bugfix release
假如fix一个bug,我们在v1版本上进行修复
修改代码如下:
// say Hi to someone
func SayHi(name string) string {
- return fmt.Sprintf("Hi, %s", name)
+ return fmt.Sprintf("Hi, %s!", name)
}
修复好,我们开始push
$ git commit -m "Emphasize our friendliness" say.go
$ git tag v1.0.1
$ git push --tags origin v1
Updating modules
刚才fix bug,所以要在我们使用项目中更新
这个需要我们手动执行更新module操作
我们通过使用我们的好朋友来做到这一点go get:
- 运行
go get -u
以使用最新的 minor 版本或修补程序版本(即它将从1.0.0更新到例如1.0.1,或者,如果可用,则更新为1.1.0) - 运行 go get -u=patch 以使用最新的 修补程序 版本(即,将更新为1.0.1但不更新 为1.1.0)
- 运行go get package@version 以更新到特定版本(例如github.com/jacksonyoudi/gomodone@v1.0.1)
目前module最新的也是v1.0.1
// 更新最新
$go get -u
$go get -u=patch
//指定包,指定版本
$go get github.com/jacksonyoudi/gomodone@v1.0.1
操作完,go.mod文件会修改如下:
module Gone
go 1.14
require (
github.com/jacksonyoudi/gomodone v1.0.1
)
Major versions
根据语义版本语义,主要版本与次要版本 不同。主要版本可能会破坏向后兼容性。从Go模块的角度来看,主要版本是 完全不同的软件包。乍一看这听起来很奇怪,但这是有道理的:两个不兼容的库版本是两个不同的库。
比如下面修改,完全破坏了兼容性。
package gomodone
import (
"errors"
"fmt"
)
// Hi returns a friendly greeting
// Hi returns a friendly greeting in language lang
func SayHi(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/jacksonyoudi/gomodone/v2
go 1.14
然后,重新tag,push
$ git commit say.go -m "Change Hi to allow multilang"
$ git checkout -b v2 # 用于v2版本,后续修复v2
$ git commit go.mod -m "Bump version to v2"
$ git tag v2.0.0
$ git push --tags origin v2
Updating to a major version
即使发布了库的新不兼容版本,现有软件 也不会中断,因为它将继续使用现有版本1.0.1。go get -u 将不会获得版本2.0.0。
如果想使用v2.0.0,代码改成如下.
package main
import (
"fmt"
"github.com/jacksonyoudi/gomodone/v2"
)
func main() {
g, err := gomodone.SayHi("Roberto", "pt")
if err != nil {
panic(err)
}
fmt.Println(g)
}
执行 go mod tidy
go: finding module for package github.com/jacksonyoudi/gomodone/v2
go: downloading github.com/jacksonyoudi/gomodone/v2 v2.0.0
go: found github.com/jacksonyoudi/gomodone/v2 in github.com/jacksonyoudi/gomodone/v2 v2.0.0
当然,两个版本都可以同时使用, 使用别名
如下:
package main
import (
"fmt"
"github.com/jacksonyoudi/gomodone"
mv2 "github.com/jacksonyoudi/gomodone/v2"
)
func main() {
g, err := mv2.SayHi("Roberto", "pt")
if err != nil {
panic(err)
}
fmt.Println(g)
fmt.Println(gomodone.SayHi("Roberto"))
}
Vendoring
默认是忽略vendor的,如果想在项目目录下有vendor可以执行下面命令
$go vendor
当然,如果构建程序的时候,希望使用vendor中的依赖,
$ go build -mod vendor
IDEA下开发GO
- 创建go项目
-
创建完项目,会自动生成go mod文件
如果需要修改,可以手动修改,加入git等操作 -
写业务逻辑代码
- 解决依赖,更新go.mod
- go build
n(gomodone.SayHi(“Roberto”))
}
### Vendoring
默认是忽略vendor的,如果想在项目目录下有vendor可以执行下面命令
```bash
$go vendor
当然,如果构建程序的时候,希望使用vendor中的依赖,
$ go build -mod vendor
IDEA下开发GO
- 创建go项目
[外链图片转存中…(img-13khfPBg-1675928204799)]
-
创建完项目,会自动生成go mod文件
如果需要修改,可以手动修改,加入git等操作 -
写业务逻辑代码
[外链图片转存中…(img-NO3dkIAi-1675928204803)]
- 解决依赖,更新go.mod
[外链图片转存中…(img-PwGP9cU8-1675928204804)]
- go build