英文:
how to handle go import absolute paths and github forks?
问题
有很多问题围绕着这个,包括为什么不应该使用import "./my/path"
以及为什么它只能工作是因为一些旧的Go代码需要它。
如果这是正确的,那么如何处理项目的封装以及扩展到GitHub分支?在其他语言中,我可以fork一个项目,或者git clone,一切都封装在那里。如何在Go项目中实现相同的行为?
以下是使用Go的“hello world”示例的简单示例。
hello.go
package main
import (
"fmt"
"github.com/golang/examples/stringutil"
)
func main() {
fmt.Printf(stringutil.Reverse("hello, world") + "\n")
}
上述代码运行得很好。但是,如果我想使用自己的stringutil,它位于一个子目录中,并且将编译为单个二进制文件,我仍然需要完整的路径:
package main
import (
"fmt"
"github.com/myrepo/examples/util/stringutil"
)
func main() {
fmt.Printf(stringutil.Reverse("hello, world") + "\n")
}
现在,如果有人复制或fork我的仓库,它就会直接依赖于“github.com/myrepo/”,尽管这完全是内部使用!
如果有20个不同的文件导入了utils/
,我需要每次有人fork时都更改每个文件吗?这将导致很多不必要的更改和无意义的git提交。
我在这里漏掉了什么?为什么相对路径是一件坏事?如何fork一个引用其自己的子目录(及其包)的项目而不更改数十个文件?
英文:
There are plenty of questions around this, including why you shouldn't use import "./my/path"
and why it only works because some legacy go code requires it.
If this is correct, how do you handle encapsulation of a project and by extension github forks? In every other lang, I can do a github fork of a project, or git clone, and everything is encapsulated there. How do I get the same behaviour out of a go project?
Simple example using the go "hello world" example.
hello.go
package main
import ("fmt"
"github.com/golang/examples/stringutil")
func main() {
fmt.Printf(stringutil.Reverse("hello, world")+"\n")
}
The above works great. But if I want to use my own stringutil which is in a subdirectory and will compile to a single binary, I still need the complete path:
package main
import ("fmt"
"github.com/myrepo/examples/util/stringutil")
func main() {
fmt.Printf(stringutil.Reverse("hello, world")+"\n")
}
Now, if someone copies or forks my repo, it has a direct dependency on "github.com/myrepo/", even though this is used entirely internally!
What if there are 20 different files that import utils/
? I need to change each one each time someone forks? That is a lot of extraneous changes and a nonsensical git commit.
What am I missing here? Why are relative paths such a bad thing? How do I fork a project that refers to its own subsidiary directories (and their packages) without changing dozens of files?
答案1
得分: 3
关于不允许相对导入的原因,你可以阅读这个讨论来了解一些观点:https://groups.google.com/forum/#!msg/golang-nuts/n9d8RzVnadk/07f9RDlwLsYJ
就个人而言,我更愿意启用相对导入,至少对于内部导入来说,正如你所描述的原因。
那么,如何处理这种情况呢?
-
如果你的分支只是从另一个项目中进行了一些小修复,并且可能很快会被接受为 PR,你可以手动编辑 git 远程仓库,将其指向你自己的 git 仓库而不是原始仓库。如果你正在使用像 godep 这样的依赖管理工具,它将能够很好地工作,因为它会将你的分支代码作为依赖进行管理,而不会直接使用
go get
。 -
如果你的分支是一个重大更改,并且你打算保持分支状态,那么你需要重写所有的导入路径。你可以使用
sed
自动化这个过程,或者你可以使用gofmt -r
来重写代码格式化时的导入路径。
[编辑] 我还找到了这个工具,它旨在帮助处理这种情况:https://github.com/rogpeppe/govers
我既使用过方法 1,也使用过方法 2。当我只需要修复某个库的小 bug 时,我只是修改了远程仓库并进行了依赖管理。当我实际上分支了一个库,并且没有意图将我的更改合并回去时,我改变了所有的导入路径,并继续只使用我的仓库。
我还可以想到一种将这些操作自动化的依赖管理工具的补充,但我认为目前没有任何一个工具支持这个功能。
英文:
As for the reasoning behind not allowing relative imports, you can read this discussion for some perspective: https://groups.google.com/forum/#!msg/golang-nuts/n9d8RzVnadk/07f9RDlwLsYJ
Personally I'd rather have them enabled, at least for internal imports, exactly for the reason you are describing.
Now, how to deal with the situation?
-
If your fork is just a small fix from another project that will probably be accepted as a PR soon - just manually edit the git remotes for it to refer to your own git repo and not the original one. If you're using a vendoring solution like godep, it will work smoothly since saving it will just vendor your forked code, and
go get
is never used directly. -
If your fork is a big change and you intend to remain forked, rewrite all the import paths. You can automate it with
sed
or you can usegofmt -r
that supports rewriting of the code being formatted.
[EDIT] I also found this tool which is designed to help with that situation: https://github.com/rogpeppe/govers
I've done both 1 and 2 - when I just had a small bugfix to some library I just changed the remote and verndored it. When I actually forked a library without intent of merging my changes back, I changed all the import paths and continued to use my repo only.
I can also think of an addition to vendoring tools allowing automation of this stuff, but I don't think any of them support it currently.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论