在 Go 中使用分叉包导入

假设您在 github.com/someone/repo有一个存储库,并将其分叉到 github.com/you/repo。你想用你的叉子而不是主回购,所以你做了一个

go get github.com/you/repo

现在,这个回购中的所有导入路径都将被“破坏”,这意味着,如果存储库中有多个包通过绝对 URL 相互引用,它们将引用源,而不是 fork。

有没有更好的方法手动将其克隆到正确的路径中?

git clone git@github.com:you/repo.git $GOPATH/src/github.com/someone/repo
35370 次浏览

这个问题的答案是,如果您使用多个包分叉一个回购,您将需要重命名所有相关的导入路径。这在很大程度上是一件好事,因为您已经分叉了所有这些包,并且导入路径应该反映这一点。

如果你的分叉只是暂时的(即你打算它被合并) ,那么只是做你的原地开发,例如在 $GOPATH/src/launchpad.net/goamz

然后使用版本控制系统的特性(例如 git remote)使上游存储库成为您的存储库,而不是原来的存储库。

它使其他人更难使用您的 go get存储库,但更容易将其集成到上游。

事实上,我在 lp:~nick-craig-wood/goamz/goamz上有一个 goamz 库,我就是以这种方式开发的。也许有一天作者会把它合并!

处理请求

  • 将存储库 github.com/someone/repo分叉到 github.com/you/repo
  • 下载原始代码: go get github.com/someone/repo
  • 待在那里: cd "$(go env GOPATH)/src"/github.com/someone/repo
  • 启用上传到您的分支: git remote add myfork https://github.com/you/repo.git
  • 上传您的变更到您的回购: git push myfork

Http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html

在项目中使用包

Https://github.com/golang/go/wiki/packagemanagementtools

解决这个问题的方法之一就是伊万 · 雷夫和 http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html提出的分叉方法。

另一个是解决 Golang行为。当您使用 go get时,Golang将使用与存储库 URI 中相同的名称来布局目录,这就是问题所在。

相反,如果您发出自己的 git clone,则可以在以原始存储库命名的路径上将存储库克隆到文件系统中。

假设原始存储库位于 github.com/awsome-org/tool中,并将其分叉到 github.com/awesome-you/tool,则可以:

cd $GOPATH
mkdir -p {src,bin,pkg}
mkdir -p src/github.com/awesome-org/
cd src/github.com/awesome-org/
git clone git@github.com:awesome-you/tool.git # OR: git clone https://github.com/awesome-you/tool.git
cd tool/
go get ./...

Golang 非常乐意继续使用这个存储库,实际上并不关心某个名为 awesome-org的上层目录,而 git Remote 是 awesome-youawesome-org的所有导入都是通过您刚刚创建的目录解决的,该目录是您的本地工作集。

更长的,请看我的博客文章: 在 GitHub 上分支 Golang 存储库并管理导入路径

编辑 : 固定目录路径

这里有一个对每个人都适用的方法:

使用 github 分叉到“ my/repo”(只是一个例子) :

go get github.com/my/repo
cd ~/go/src/github.com/my/repo
git branch enhancement
rm -rf .
go get github.com/golang/tools/cmd/gomvpkg/…
gomvpkg <<oldrepo>> ~/go/src/github.com/my/repo
git commit

当您使代码更好时,每次都要重复:

git commit
git checkout enhancement
git cherry-pick <<commit_id>>
git checkout master

为什么?这让你有你的回购,任何 go get的工作。它还可以让你维护和增强一个分支,这是一个很好的拉请求。它不会用“供应商”来膨胀 git,它保留了历史,构建工具可以理解它。

为了使这个过程自动化,我编写了一个小脚本。您可以在我的 博客中找到更多细节,以便向 bash 添加类似“ gofork”的命令。

function gofork() {
if [ $# -ne 2 ] || [ -z "$1" ] || [ -z "$2" ]; then
echo 'Usage: gofork yourFork originalModule'
echo 'Example: gofork github.com/YourName/go-contrib github.com/heirko/go-contrib'
return
fi
echo "Go get fork $1 and replace $2 in GOPATH: $GOPATH"
go get $1
go get $2
currentDir=$PWD
cd $GOPATH/src/$1
remote1=$(git config --get remote.origin.url)
cd $GOPATH/src/$2
remote2=$(git config --get remote.origin.url)
cd $currentDir
rm -rf $GOPATH/src/$2
mv $GOPATH/src/$1 $GOPATH/src/$2
cd $GOPATH/src/$2
git remote add their $remote2
echo Now in $GOPATH/src/$2 origin remote is $remote1
echo And in $GOPATH/src/$2 their remote is $remote2
cd $currentDir
}


export -f gofork

一起使用供应商和子模块

  1. 在 github 上分叉 lib (本例中为 go-mssqldb)
  2. 添加一个 子舱,它克隆你的叉到你的 供应商文件夹,但有上游回购的路径
  3. 更新源代码中的 import语句以指向供应商文件夹(不包括 vendor/前缀)。例如: vendor/bob/lib = > import "bob/lib"

例如。

cd ~/go/src/github.com/myproj


mygithubuser=timabell
upstreamgithubuser=denisenkom
librepo=go-mssqldb


git submodule add "git@github.com:$mygithubuser/$librepo" "vendor/$upstreamgithubuser/$librepo"

为什么

这解决了 所有的问题,我已经听说过和遇到的时候,试图弄清楚这一点自己。

  • 现在库中的内部包引用可以工作了,因为路径与上游路径没有变化
  • 项目的新签出可以正常工作,因为子模块系统在正确的提交时从分叉处获取,但是在上游文件夹路径中
  • 您不必知道手动修改路径或者干扰 Go 工具。

更多信息

如果您正在使用 去模块。您可以使用 replace指令

replace指令允许您提供另一个可能的导入路径 是位于 VCS (GitHub 或其他地方)的另一个模块,或在您的 具有相对或绝对文件路径的本地文件系统 使用来自 replace指令的路径,无需更新 导入实际源代码中的路径。

因此,您可以在 go.mod 文件中执行以下操作

module some-project


go 1.12


require (
github.com/someone/repo v1.20.0
)


replace github.com/someone/repo => github.com/you/repo v3.2.1

其中 v3.2.1是标签在您的回购。也可以通过 CLI

go mod edit -replace="github.com/someone/repo@v0.0.0=github.com/you/repo@v1.1.1"

Gopkg.toml文件中添加以下代码块

[[constraint]]
name = "github.com/globalsign/mgo"
branch = "master"
source = "github.com/myfork/project2"

因此它将使用分叉的 project2代替 github.com/globalsign/mgo

您可以使用命令 go get -f获得一个分叉回购

您可以在任何想要的地方进行克隆,而不是将其克隆到特定的位置。 然后,您可以运行这样的命令,让 Go 引用本地版本:

go mod edit -replace github.com/owner/repo=../repo

Https://golang.org/cmd/go#hdr-module_maintenance

现代的答案(至少是1.15或更高)。

go mod init github.com/theirs/repo

创建一个显式的 init 参数,即 ORIGINAL 包名称。如果你不包括回购的名称,它会假设一个在反义词。但是当您使用 go 模块时,它们不再关心它们在磁盘上的位置,或者 git 实际上从哪里获取依赖项。