赞
踩
很久没更新了,一是工作琐碎,二是处在舒适区,但最近看着身边的同事一个个离开,危机感骤然而生,不得不重拾书本,毕竟生活还得继续,不卷是不可能的,谁让我们生在这个卷中卷的国度,只能活到老卷到老…
说完题外话,说说正题,笔者使用 Golang 也有两三年了,基本还停留在会用就行,没有深挖细节,不符合我刨根问底的学习习惯,接下来一段时间,准备系统的看看 go 官方文档,毕竟这是最新最权威的资料,然后顺手写点东西,就当是加深映像吧。
今天要说的是我们怎么在项目里使用fork的别人的模块,因为fork别人的项目之后,项目的路径和 go.mod 里声明的路径就不一样了,直接 go get 是引入不了的,比如这里引入我 fork 后的 github.com/zhyee/gin 框架会报错:
$ go get github.com/zhyee/gin
go: downloading github.com/zhyee/gin v0.0.0-20240119001857-857db39f82fb
go: github.com/zhyee/gin@v0.0.0-20240119001857-857db39f82fb: parsing go.mod:
module declares its path as: github.com/gin-gonic/gin
but was required as: github.com/zhyee/gin
那是不是我把 go.mod 里的 module 声明 github.com/gin-gonic/gin 改成fork 后的项目地址 github.com/zhyee/gin 就完事了呢,当然不是,通常一个 go模块下的各个子 package 之间的相互引用也是用的带模块名的绝对路径而不是相对路径(参考下方截图),所以除了要改 go.mod 里的 module 声明,还要修改子package相互导入的包名路径,这对于一个较大型的项目涉及到的修改地方就太多了,即使你可以全文替换把整个项目里出现的原模块名全部替换掉,并且确实也能正常使用了,那假如将来你希望把自己的fork版本提个PR合并进原始项目时,是不是又要把模块名改回来呢,这种做法显然不太科学,go官方当然也考虑到了这种常见的使用场景。

比较通用的做法是使用 replace 指令,比如
$ cat go.mod module example.com/hello go 1.20 require golang.org/x/example/hello v0.0.0-20231013143937-1d6d2400d402 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect )
我们可以使用命令 go mod edit -replace=old[@v]=new[@v] 来添加 replace 指令,也可以直接编辑 go.mod 文件来添加,old[@v] 中的版本号如果省略,则表明所有的版本都应该被替换,否则只有指定的版本会执行替换,new[@v] 模块中的版本号如果被省略,则用于替换的模块应该是一个本地模块而不是网络模块
$ $ go mod edit -replace=github.com/gin-gonic/gin=github.com/zhyee/gin@latest $ $ cat go.mod module example.com/hello go 1.20 require golang.org/x/example/hello v0.0.0-20231013143937-1d6d2400d402 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/gin-gonic/gin => github.com/zhyee/gin latest
添加replace指令之后再次执行 go get github.com/gin-gonic/gin 会发现又会重新拉下来一些东西:
$ go get github.com/gin-gonic/gin
go: upgraded github.com/go-playground/validator/v10 v10.14.0 => v10.16.0
go: upgraded github.com/pelletier/go-toml/v2 v2.0.8 => v2.1.1
go: upgraded golang.org/x/crypto v0.9.0 => v0.15.0
go: upgraded golang.org/x/net v0.10.0 => v0.18.0
go: upgraded golang.org/x/sys v0.8.0 => v0.14.0
go: upgraded golang.org/x/text v0.9.0 => v0.14.0
为了证明我们现在用的Gin已经替换为 github.com/zhyee/gin 而不是官方的github.com/gin-gonic/gin,我们可以在 IDE里查看gin的相关源码,可以看到IDE已经为我们自动跳转到了替换后的项目:

那如果我们fork出来的项目随着时间的推移有了新版本了,该如何在go项目里升级 replace 的module呢,比如这里我给我fork出来的 github.com/zhyee/gin 打了一个新的tag v1.99.99:

我现在想升级到该 v1.99.99版本,你可以直接修改 replace指令,把老的版本号替换为新的版本号,比如把
replace github.com/gin-gonic/gin => github.com/zhyee/gin v0.0.0-20240119001857-857db39f82fb 替换为 replace github.com/gin-gonic/gin => github.com/zhyee/gin v1.99.99 ,或者 replace github.com/gin-gonic/gin => github.com/zhyee/gin latest,然后执行一下 go get github.com/gin-gonic/gin 或 go mod tidy:
$ go mod edit -replace=github.com/gin-gonic/gin=github.com/zhyee/gin@latest $ $ cat go.mod module example.com/hello go 1.20 require github.com/gin-gonic/gin v1.9.1 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/gin-gonic/gin => github.com/zhyee/gin latest $ $ go get github.com/gin-gonic/gin go: downloading github.com/zhyee/gin v1.99.99 $ $ cat go.mod module example.com/hello go 1.20 require github.com/gin-gonic/gin v1.9.1 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/gin-gonic/gin => github.com/zhyee/gin v1.99.99 $
如果使用了 go mod 代理,可能有时代理还没有缓存某个module的最新版本,这时建议暂时关闭代理或者使用具体的版本号而不是 latest:
$ cat go.mod module example.com/hello go 1.20 require github.com/gin-gonic/gin v1.9.1 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/gin-gonic/gin => github.com/zhyee/gin v1.99.99 $ $ go mod edit -replace=github.com/gin-gonic/gin=github.com/zhyee/gin@v1.99.999 $ $ cat go.mod module example.com/hello go 1.20 require github.com/gin-gonic/gin v1.9.1 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/gin-gonic/gin => github.com/zhyee/gin v1.99.999 $ $ $ go get github.com/gin-gonic/gin go: downloading github.com/zhyee/gin v1.99.999 $ $ cat go.mod module example.com/hello go 1.20 require github.com/gin-gonic/gin v1.9.1 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/gin-gonic/gin => github.com/zhyee/gin v1.99.999 $ $ go run . my forked Gin framework v1.99.999 [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
之前我们也说了,省略替换后模块 new[@v] 中的版本号,则应该指定一个本地的模块路径,所以我们也可以把module克隆到本地,然后用 replace 指令把某个模块替换为本地的模块,这种方式在开发阶段比较好用,不需要频繁把修改推到fork后的远端仓库就可以直接调试运行看到效果:
$ ls example go.work hello $ $ git clone https://github.com/zhyee/gin.git Cloning into 'gin'... remote: Enumerating objects: 7298, done. remote: Counting objects: 100% (1915/1915), done. remote: Compressing objects: 100% (248/248), done. remote: Total 7298 (delta 1772), reused 1670 (delta 1667), pack-reused 5383 Receiving objects: 100% (7298/7298), 3.08 MiB | 843.00 KiB/s, done. Resolving deltas: 100% (4745/4745), done. $ $ cd hello/ $ $ go mod edit -replace=github.com/gin-gonic/gin=../gin $ $ cat go.mod module example.com/hello go 1.20 require golang.org/x/example/hello v0.0.0-20231013143937-1d6d2400d402 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.15.0 // indirect golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/gin-gonic/gin => ../gin
然后对我们克隆下来的 Gin 做一点修改(这里添加了一个init方法,打印一句话,方便查看效果), 然后编译运行我们的 hello 项目

$ cd hello/ $ ls go.mod go.sum hello.go $ $ cat hello.go package main import ( "github.com/gin-gonic/gin" ) func main() { gin.New() } $ $ go run . my forked Gin framework [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
可以看到已经应用了我们本地的 Gin代码。
Golang 1.18版本新增了一个 workspace 的概念,通常一个go项目就是一个 go 模块,但一个workspace 能包含多个 go模块,方便多个模块之间的相互调用,以及多个模块的同时开发,从而形成go的 package、module、workspace 三层代码组织级别。
在没有workspace 的情况下,想要在 module 目录外编译和运行 module 是比较困难的,比如:
$ ll foobar/
total 16
-rw-r--r-- 1 zy staff 35 1 26 14:02 go.mod
-rw-r--r-- 1 zy staff 73 1 26 14:02 main.go
$
$ go run foobar/
package foobar is not in GOROOT (/Users/zy/go1.20.10/src/foobar)
提示package在 $GOROOT/src目录下找不到,即使把module放到 $GOPATH/src 路径下也还是会报错:
$ go env GOPATH
/Users/zy/go
$
$ ll /Users/zy/go/src/foobar/
total 16
-rw-r--r-- 1 zy staff 23 1 26 14:28 go.mod
-rw-r--r-- 1 zy staff 73 1 26 13:25 main.go
$
$ go run /Users/zy/go/src/foobar/
go: go.mod file not found in current directory or any parent directory; see 'go help modules'
提示在当前目录或是父级目录找不到 go.mod 文件,workspace的出现解决了这个问题:
$ mkdir goworkspace $ cd goworkspace/ $ $ go work init $ $ ls go.work $ cat go.work go 1.20 $ $ mv ../foobar/ ./ $ ls foobar go.work $ go work use foobar/ $ SpaceX:goworkspace zy$ cat go.work go 1.20 use ./foobar $ $ go run foobar/ hello foobar $
go work init 命令会把当前目录作为一个workspace并创建一个go.work 文件,类似于 go mod init,go work use moddirs 会把指定的module加入到当前workspace的主模块当中。同一个workspace中的各个模块之间相互调用是非常方便的,比如:
$ ls foobar go.work SpaceX:goworkspace zy$ $ mkdir foolib $ cd foolib/ $ $ go mod init "example.com/go/foolib" go: creating new go.mod: module example.com/go/foolib $ $ ls go.mod $ cat go.mod module example.com/go/foolib go 1.20 $ $ vi lib.go $ SpaceX:foolib zy$ cat lib.go package foolib func Add(a, b int) int { return a * b } $ $ cd .. $ ls foobar foolib go.work $ cat go.work go 1.20 use ./foobar $ $ go work use foolib/ $ $ cat go.work go 1.20 use ( ./foobar ./foolib ) $ go build ./foolib/ $ $ vi foobar/main.go $ $ cat foobar/main.go package main import "fmt" import "example.com/go/foolib" func main() { fmt.Println("hello foobar") fmt.Println("foolib Add: ", foolib.Add(4, 5)) } $ $ go run foobar/ hello foobar foolib Add: 20
上述操作在 workspace 中创建了另一个module example.com/go/foolib,然后使用 go work use 命令把它加入到workspace中,最后在原来的 foobar 模块中调用 example.com/go/foolib 中提供的方法,一切都是那么的简单,不需要replace指令,不需要关注module所在的路径是否与module 声明中的一致,不需要处理模块之间的相对路径,使用起来和 go get 一样的优雅。
当然,go.work 中也支持使用 replace 指令,且该指令对workspace下的所有 module 都生效:
$ ls foobar foolib go.work $ $ go work edit -replace=github.com/gin-gonic/gin=/Users/zy/project/gin $ SpaceX:goworkspace zy$ cat go.work go 1.20 use ( ./foobar ./foolib ) replace github.com/gin-gonic/gin => /Users/zy/project/gin $ $ mkdir foo bar $ $ $ cd foo && go mod init "foo" go: creating new go.mod: module foo $ $ cd .. $ cd bar && go mod init "bar" go: creating new go.mod: module bar $ $ $ cd .. $ ls bar foo foobar foolib go.work $ $ vi foo/main.go $ $ cp foo/main.go bar/ $ $ cat foo/main.go package main import "github.com/gin-gonic/gin" func main() { gin.New() } $ cat bar/main.go package main import "github.com/gin-gonic/gin" func main() { gin.New() } $ $ go work use foo/ bar/ $ $ cat go.work go 1.20 use ( ./bar ./foo ./foobar ./foolib ) replace github.com/gin-gonic/gin => /Users/zy/project/gin $ $ cd foo $ go get github.com/gin-gonic/gin go: added github.com/bytedance/sonic v1.9.1 go: added github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 go: added github.com/gabriel-vasile/mimetype v1.4.2 go: added github.com/gin-contrib/sse v0.1.0 go: added github.com/gin-gonic/gin v1.9.1 go: added github.com/go-playground/locales v0.14.1 go: added github.com/go-playground/universal-translator v0.18.1 go: added github.com/go-playground/validator/v10 v10.14.0 go: added github.com/goccy/go-json v0.10.2 go: added github.com/json-iterator/go v1.1.12 go: added github.com/klauspost/cpuid/v2 v2.2.4 go: added github.com/leodido/go-urn v1.2.4 go: added github.com/mattn/go-isatty v0.0.19 go: added github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd go: added github.com/modern-go/reflect2 v1.0.2 go: added github.com/pelletier/go-toml/v2 v2.0.8 go: added github.com/twitchyliquid64/golang-asm v0.15.1 go: added github.com/ugorji/go/codec v1.2.11 go: added golang.org/x/arch v0.3.0 go: added golang.org/x/crypto v0.9.0 go: added golang.org/x/net v0.10.0 go: added golang.org/x/sys v0.8.0 go: added golang.org/x/text v0.9.0 go: added google.golang.org/protobuf v1.30.0 go: added gopkg.in/yaml.v3 v3.0.1 $ $ cat go.mod module foo go 1.20 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) $ cd .. $ go run ./foo my forked Gin framework [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) $ cd bar/ $ $ go get github.com/gin-gonic/gin go: added github.com/bytedance/sonic v1.9.1 go: added github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 go: added github.com/gabriel-vasile/mimetype v1.4.2 go: added github.com/gin-contrib/sse v0.1.0 go: added github.com/gin-gonic/gin v1.9.1 go: added github.com/go-playground/locales v0.14.1 go: added github.com/go-playground/universal-translator v0.18.1 go: added github.com/go-playground/validator/v10 v10.14.0 go: added github.com/goccy/go-json v0.10.2 go: added github.com/json-iterator/go v1.1.12 go: added github.com/klauspost/cpuid/v2 v2.2.4 go: added github.com/leodido/go-urn v1.2.4 go: added github.com/mattn/go-isatty v0.0.19 go: added github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd go: added github.com/modern-go/reflect2 v1.0.2 go: added github.com/pelletier/go-toml/v2 v2.0.8 go: added github.com/twitchyliquid64/golang-asm v0.15.1 go: added github.com/ugorji/go/codec v1.2.11 go: added golang.org/x/arch v0.3.0 go: added golang.org/x/crypto v0.9.0 go: added golang.org/x/net v0.10.0 go: added golang.org/x/sys v0.8.0 go: added golang.org/x/text v0.9.0 go: added google.golang.org/protobuf v1.30.0 go: added gopkg.in/yaml.v3 v3.0.1 $ $ cat go.mod module bar go 1.20 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) $ cd .. $ $ go run ./bar/ my forked Gin framework [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) $ $
上述操作新建了两个module foo 和 bar,并加入到了 workspace 中,两个 module 都调用了 Gin 框架,但在各自的 go.mod 中都没有使用 replace 指令替换 github.com/gin-gonic/gin,但在 workspace中的 go.work 中把 github.com/gin-gonic/gin 替换为了本地修改过的 /Users/zy/project/gin,可以看到go.work中的replace 指令最终对 foo 和 bar 两个模块都生效了,可见workspace可以方便的统一管理多模块。
上面花了大量的篇幅介绍go workspace,还没有说怎么在项目里使用 fork后的module,其实就是把fork后的项目克隆到workspace下,然后使用 go work use指令把module加入到主模块中,然后就可以直接用这个模块了,效果和使用 replace 指定本地模块路径差不多:
$ cd ~/project/goworkspace/ $ $ ls bar foo foobar foolib go.work go.work.sum $ $ git clone https://github.com/zhyee/gin.git Cloning into 'gin'... remote: Enumerating objects: 7304, done. remote: Counting objects: 100% (3106/3106), done. remote: Compressing objects: 100% (416/416), done. remote: Total 7304 (delta 2861), reused 2696 (delta 2690), pack-reused 4198 Receiving objects: 100% (7304/7304), 3.02 MiB | 6.00 MiB/s, done. Resolving deltas: 100% (4813/4813), done. $ $ ls bar foo foobar foolib gin go.work go.work.sum $ $ go work use gin $ $ cat go.work go 1.20 use ( ./bar ./foo ./foobar ./foolib ./gin ) replace github.com/gin-gonic/gin => /Users/zy/project/gin $ $ go work edit -dropreplace=github.com/gin-gonic/gin $ $ cat go.work go 1.20 use ( ./bar ./foo ./foobar ./foolib ./gin ) $ $ cat foo/go.mod module foo go 1.20 require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) $ cat foo/main.go package main import "github.com/gin-gonic/gin" func main() { gin.New() } $ $ go run foo/ my forked Gin framework v1.99.999 [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
当然这种方式适合开发阶段,如果你fork别人的module已经稳定了,或者你引用fork模块的项目已经到了测试发布阶段了,还是要用 replace 指令。
完!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。