如何处理Go导入绝对路径和GitHub分支?

huangapple go评论76阅读模式
英文:

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

就个人而言,我更愿意启用相对导入,至少对于内部导入来说,正如你所描述的原因。

那么,如何处理这种情况呢?

  1. 如果你的分支只是从另一个项目中进行了一些小修复,并且可能很快会被接受为 PR,你可以手动编辑 git 远程仓库,将其指向你自己的 git 仓库而不是原始仓库。如果你正在使用像 godep 这样的依赖管理工具,它将能够很好地工作,因为它会将你的分支代码作为依赖进行管理,而不会直接使用 go get

  2. 如果你的分支是一个重大更改,并且你打算保持分支状态,那么你需要重写所有的导入路径。你可以使用 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?

  1. 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.

  2. 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 use gofmt -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.

huangapple
  • 本文由 发表于 2015年8月23日 20:27:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/32166642.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定