请教大神一个 golang 中依赖模块 fork 修改使用的问题

345 天前
 zhwguest

假设我的项目中 require 了一个第三方 github.com/old/dep 模块,依赖的版本是 v1.2.3 。

现在我对该依赖 fork 出来做了修改,放到 github.com/new/dep 上,然后我想依赖于新的模块。

不知道推荐的方法是什么?

方法 1:仍然 require github.com/old/dep v1.2.3 ,用 replace 将其替换到新的地址?那版本号怎么处理呢?毕竟我有了新的提交,打 tag 肯定不能是 v1.2.3 了,重新 tag 为 v1.2.4 ,这该如何写 replace 呢?以后不会混乱么?

方法 2:干脆和 github.com/old/dep 模块分离,直接在项目中 require github.com/new/dep 。但是这个项目中有很多源代码是直接 import 的 github.com/old/dep/xxx 。使用 gohack ?

1029 次点击
所在节点    Go 编程语言
11 条回复
kuanat
345 天前
用你方法一的思路,replace 是支持版本号映射的,比如

require github.com/old/dep v1.2.3 => github.com/new/dep v1.2.4

另外也可以 github.com/new/dep@dev 指定分支。

你说的方法二有个问题:就像你说的,如果它包含子模块,这些子模块还是会引用 /old/dep ,那 fork 出来需要修改的地方就非常多。

具体怎么做取决于 /new/dep 这个 fork 的定位。仅仅打个补丁,需要定期合并上游 /old/dep 那就用方法一。如果是要大刀阔斧另起炉灶,那就方法二吧。

关于版本号,我的建议是保持一致。就是你在 v1.2.3 上的改版,就用 v1.2.3 发布,特别是你仅仅要做个小改动的时候。不过这个事情不重要,你清楚对应的版本就可以了,而且几乎做不到一一对应。

另外这里要注意 go sum 机制,改版 /new/dep 发布之后 github.com/new/dep v1.2.3 校验信息会被 google 缓存。这个时候如果对 /new/dep 做了多次修改,就只能升版本或者换分支了。
javalaw2010
345 天前
如果你的 fork 打算 merge 到上游,用 replace ,如果你的改动比较私人,不希望或者不太可能合并到上游,就用/new/dep
vultr
344 天前
如果可以的话,最好是合并回上游。
zhwguest
341 天前
谢谢大家的帮助。
@kuanat 衷心感谢,另外我还想问一下,如果我保持版本号不变,那么 tag 不是会冲突么?谢谢
kuanat
341 天前
@zhwguest #4

可能之前没表达清楚,这里应该不存在冲突的。


比如说你一开始用的 /old/dep 依赖,那么在 go.mod 里面就会有

require github.com/old/dep v1.2.3

只要你不升级依赖,那么整个项目一直会用 /old/dep v1.2.3

然后你 fork 了 /new/dep 出来,并且给 /new/dep 打了版本 v1.2.3
这个时候增加一句

replace github.com/old/dep v1.2.3 => github.com/new/dep v1.2.3

就可以了。

假如 /old/dep 更新过后,你发现没有必要用 /new/dep 了,那就把上面的删掉,然后更新依赖到比如说 /new/dep v1.2.4 ,不管是 go get -u 还是手动修改 go.mod ,最终 go.mod 都会是

require github.com/old/dep v1.2.4

假如你还是要用 /new/dep ,不管你是继续在 /new/dep 上修改,还是合并了 /old/dep 的上游更新,然后打了 v1.2.4 的版本,只需要修改 replace 这一句变成

replace github.com/old/dep v1.2.3 => github.com/new/dep v1.2.4

但是 require 那一句还保持

require github.com/old/dep v1.2.3



也就是说,只要你不主动升级 /old/dep 的版本,那就只需要修改 replace 的目标版本。至于 /new/dep 怎么打版本 tag 是随意的。

之前说保持版本号一致只是应对两种场景,一种是 /new/dep 作为临时开发测试分支,有可能被 /old/dep 合并,当 /old/dep 更新之后又会回到 /old/dep 上面去。另一种是 /new/dep 是因为某些原因不可能被 /old/dep 合并,但是修改可以通过 patch 的方式自动化,上游 /old/dep 发布一个版本,下游 /new/dep 就发布一个对应的修改版。



默认情况下,github 的 fork 功能,是不带 tag 的,所以你可以在 fork 里面重新任意标记版本。假如你不想处理 tag 相关的事情,也可以完全不理会。这种情况下,replace 后面改成 /new/dep 就行了,go.sum 会用 v0.0.0-timestamp-commit_hash 的方式来唯一确定。
zhwguest
337 天前
@kuanat 明白了,非常感谢热心解答。
zhwguest
337 天前
@kuanat 关于 tag 的问题还想请教一下,比如上游 git 的版本是 1.2.3 ,我现在将其 tag 为 1.2.4 ,那下次上游 tag 升级为 1.2.4 的时候,我的 tag 不是和它冲突了么?所以是不是本身不建议 tag ?
zhwguest
337 天前
我如果不管 tag ,总是用最新的:

replace github.com/old/dep v1.2.3 => github.com/new/dep

这样好像是提示错误的。
kuanat
336 天前
@zhwguest #8

git tag 是与 repo 相关的,/old/dep 和 /new/dep 是相互独立的,我不确定你说的冲突,只要同一个 repo 里面 tag 唯一就可以。

一般不建议 => 左边带版本,除非你的项目永远不升级依赖。如果左边带版本 v1.2.3 ,就代表只有这个特定版本会被替换,但是上游更新 v1.2.4 然后你 go get -u 升级了依赖,那 v1.2.3 的替换就失效了。不带版本就是所有版本都会替换。

右边只有替换成本地 repo 的时候才可以不带版本。
liaoyuan6666
336 天前
@zhwguest 要指定 hast 或版本的
liaoyuan6666
336 天前
hash 打错了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1000112

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX