go.work

随着go 1.18版本的正式发布,多模块工作区也被引入(WorkSpaces),多模块工作区能够使开发者能够更容易地同时处理多个模块的工作, 如:方便进行依赖的代码调试(打断点、修改代码)、排查依赖代码 bug 。方便同时进行多个仓库/模块并行开发调试。

起因

本地有两个项目,分别是两个 module:example1 和 example2。

在 example1 的 bar.go 中有如下代码:

package example1

func Bar() {
    println("This is package example1")
}

接着,在 example2 模块中 main.go 中有如下内容:

package main

import (
    "github.com/test/example1"
)

func main() {
    example1.Bar()
}

这时候,如果运行 go mod tidy,肯定会报错,因为 example1 包根本没有提交到 github 上,找不到。

$ go mod tidy
....
fatal: repository 'https://github.com/test/example1/' not found

当然可以提交 example1 到 github,但每修改一次 example1,就需要提交(而且每次提交之后需要在 example2 中 go get 最新版本),否则 example2 中就没法使用上最新的。

针对这种情况,可以通过 replace 来解决,即在 example2 中的 go.mod 增加如下 replace:

module github.com/test/example2

go 1.19

require github.com/test/example1 v1.0.0

replace github.com/test/example1 => ../example1

当都开发完成时,需要手动删除 replace,并执行 go mod tidy 后提交,否则别人使用就报错了。

这还是挺不方便的,如果本地有多个 module,每一个都得这么处理。

工作区模式

针对上面的这个问题,Michael Matloob 提出了 Workspace Mode(工作区模式)。并在 Go1.18 中发布了。

注意:工作区不只是 go work 相关命令,Go 其他命令也会涉及工作区内容,比如 go run、go build 等。

初始化 workspace:

$ cd ~/test
$ go work init example1 example2
$ tree
.
├── example2
│   ├── go.mod
│   └── main.go
├── go.work
└── example1
    ├── bar.go
    └── go.mod

注意几点:

  • 多个子模块应该在一个目录下(或其子目录)。比如这里的 test 目录;(这不是必须的,但更好管理,否则 go work init 需要提供正确的子模块路径)
  • go work init 需要在 example1 目录执行;
  • go work init 之后跟上需要本地开发的子模块目录名;
go 1.23

use (
    ./example1
    ./example2
)

注意:实际项目中,多个模块之间可能还依赖其他模块,建议在 go.work 所在目录执行 go work sync

注意,go.work 不需要提交到 Git 中,因为它只是你本地开发使用的。

当开发完成,应该先提交 example1 包到 GitHub,然后在 example2 下面执行 go get:

$ go get -u github.com/test/example1@latest

然后禁用 workspace(通过 GOWORK=off 禁用),再次运行 example2 模块,是否正确:

$ cd ~/test/example2
$ GOWORK=off go run main.go

在同时使用go.work和go.mod的replaces功能时,分别指定不同的代码仓库路径,go.work优先级高于go.mod中定义

//go.mod 中定义替换为本地仓库 example
replace ( 
    github.com/link1st/example => ./example 
)

//go.work 中定义替换为本地仓库 example1
replace ( 
    github.com/link1st/example => ./example1 
)

在代码构建时,使用的是go.work指定的example1仓库代码,go.work优先级别更高

go work支持命令

  • go work init 初始化工作区文件,用于生成go.work工作区文件

初始化并写入一个新的go.work到当前路径下,可以指定需要添加的代码模块

eg: go work init ./hello 将本地仓库hello添加到工作区

hello仓库必须是go mod依赖管理的仓库

  • go work use添加新的模块到工作区

eg:

go work use ./example 添加一个模块到工作区

go work use ./example ./example1 添加多个模块到工作区

go work use -r ./example 递归./example目录到当前工作区

删除命令: go work edit -dropuse=./example 功能

  • go work sync将工作区的构建列表同步到工作区模块,go.work 文件中会列出多个模块路径,当在这些模块的 go.mod 文件中修改了依赖版本后,运行 go work sync 会更新工作空间中其他模块的依赖信息,保证一致性。
  • go env GOWORK查看环境变量,查看当前工作区文件路径,可以排查工作区文件是否设置正确,go.work路径找不到可以使用GOWORK指定
Last Updated:
Contributors: liushun-ing