在Go中使用分叉包导入


104

假设您有一个存储库,github.com/someone/repo然后将其分叉到github.com/you/repo。您想使用fork而不是主仓库,因此您需要

go get github.com/you/repo

现在,此存储库中的所有导入路径都将“断开”,这意味着,如果存储库中有多个通过绝对URL相互引用的包,则它们将引用源而不是派生。

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

git clone git@github.com:you/repo.git $GOPATH/src/github.com/someone/repo

1
新分支中的任何导入路径都不会被破坏,而在分支之前尚未被破坏。
zzzz

11
抱歉让您失望,但这不是事实。如果通过绝对URL在导入中引用了子包,则此导入将在派生中中断(或至少引用错误的包)。
Erik Aigner 2013年

2
例如goamz。它到处都有内部引用。
Erik Aigner 2013年

1
查看ec2包装-它具有launchpad.net/goamz/aws进口。两者中,aws并且ec2包驻留在相同的存储库中,所以叉形时,不会引用正确包(一个在叉)。
Erik Aigner 2013年

1
分支将引用与分支的源相同的包。那有什么不对?fork将编译,构建,将执行与以前相同的操作。那么“不正确的包装”的定义是什么?请注意,Go语言及其构建系统对存储库没有任何了解,只有软件包。
zzzz

Answers:


84

处理拉取请求

  • 将存储库派生github.com/someone/repogithub.com/you/repo
  • 下载原始代码: go get github.com/someone/repo
  • 在那里: cd "$(go env GOPATH)/src"/github.com/someone/repo
  • 启用上传到您的fork: 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


我应该从哪个文件夹做git remote add?从叉子克隆?从原始克隆?从内部走?
lapots

1
@lapots在原始存储库中运行命令(即$ GOPATH / src / github.com / somone / repo)
will7200 '18

如果我想对很久以前创建的仓库添加更改怎么办?
适用

61

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

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

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

module github.com/yogeshlonkar/openapi-to-postman

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"

4
很棒。我认为没有更多投票的唯一原因是因为人们还没有使用go模块。我还使用此技巧将文件位置指向工作站上我正在进行本地编辑的另一个目录。一旦在github中推送本地编辑,我就删除我的“替换”行。
lazieburd

^ 100%同意。投票给人。
安德鲁·阿罗

2
哦,但是“主人”对我没有用。我必须在那里编写v0.0.1或某些特定版本。
安德鲁·阿罗

1
您也可以go mod edit -replace 直接在命令行上:go mod edit -replace="github.com/someone/repo@v0.0.0=github.com/you/repo@v1.1.1"。两者@v...都是可选的。
乔尔·普拉

拥有一个角色go.mod.localgo.mod.dev实际上代替导入本地开发路径的人会很酷吗?我的意思是,您将永远不会忘记删除丑陋的“替换”,因为您不必这么做。
曼努埃尔

21

解决它的一种方法是Ivan Rave和http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html提出的 -分叉的方法。

另一个是解决golang行为。当您使用golanggo get,目录的名称与存储库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-orggit remote是的上层目录的名称awesome-you。所有的导入awesome-org都通过您刚刚创建的目录(本地工作集)进行。

详细内容请参见我的博客文章:在GitHub上分叉Golang存储库并管理导入路径

编辑:固定目录路径


3
我同意这是“最佳”解决方案。但是,很高兴看到人们在Docker容器中运行Go应用时如何管理该工作流程。我正在学习golang,想在创建Pull Request之前遇到麻烦来对其进行测试时,向正在使用的库中添加一个微小的功能。
阿金(Joakim)

6

如果您的叉子只是临时的(即您打算将其合并),则只需在原位进行开发,例如在中$GOPATH/src/launchpad.net/goamz

然后,您可以使用版本控制系统的功能(例如git remote)将上游存储库变成您的存储库,而不是原始存储库。

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

实际上,我有一个用于goamz的存储库,正是以lp:~nick-craig-wood/goamz/goamz这种方式在该存储库上进行开发。也许作者有一天会合并它!


1
只是我了解这样做的含义,如果我走这条路线,当有人go get从我的仓库中执行a时,我所有的import语句等仍然会反映出来github.com/original_author,因此被破坏了……对吗?
parker.sikand 2014年

@ parker.sikand是的,这是正确的。这项技术最适合您打算在上游合并的内容,而不是用于使用的内容。如果您打算永久分叉包装,请使用其他答案的技术。
Nick Craig-Wood

4

这是一种适用于所有人的方法:

使用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,它可以保留历史,并且构建工具可以理解它。


稍作修正:运行github.com/golang/tools/cmd/gomvpkg/main.go,此命令将.git移至其他位置,因此请将其保存到其他位置,然后将其还原。
user1212212

也有可能只是使用MVN-golang插件,它使得一些自动化比如上例中的依赖关系处理github.com/raydac/mvn-golang/tree/master/mvn-golang-examples/...
伊戈尔Maznitsa

3

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


3
在我对Go项目的第一篇贡献中,我花费了很多时间不愿意诊断出这一点。“所有测试都通过了,包括我为详尽测试新功能而编写的测试。这是怎么回事?!” 您是否知道有任何工具可以缓解初学者的这个绊脚点?
Sage Mitchell

3
一旦弄清楚了,使用findxargs和即可轻松解决sed,但是这将有助于拥有一个始终如一的对所有人有效的工作流程。
Sage Mitchell

@JakeMitchell gomvpkg可以使更改更容易/更好。go get golang.org/x/tools/cmd/gomvpkg然后gomvpkg -help
Dave

3
这个答案使我感到震惊,因为它不切实际。从分支项目中读取项目文件,这很疯狂吗?创建请求请求时该怎么办?Ivan Rave的答案对我来说似乎是一个更好的解决方案。
伊万·P

8
这仍然是Go-lang的工作方式吗?这太疯狂了,以至于不好笑……要么对上游友好,要么对下游友好,但不能两者兼而有之。在我看来,这是一个巨大的设计缺陷,可能是由交叉项目合作不多的人完成的。#FAIL #GOLANG
Niclas Hedhman '16

1

为了使这一过程自动化,我编写了一个小脚本。您可以在我的博客上找到更多详细信息,以便在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

应该golang更改为gofork第4行?
Dan Tenenbaum

好看!固定!
heralight

1

一起使用供应商和子模块

  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"

为什么

这解决了我自己发现并遇到的所有问题。

  • 库中的内部软件包引用现在可以正常工作,因为从上游开始,路径未发生变化
  • 项目的全新签出是可行的,因为子模块系统在正确的提交但在上游文件夹路径中从您的fork获取了它
  • 您不必知道手动修改路径或使用go工具。

更多信息


0

在您的Gopkg.toml文件中,在下面添加这些代码块

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

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


Gopkg.toml仅使用dep此问题根本没有提及的文件。新的Go项目应改为使用Go模块(并且IMO现有的基于dep的项目也应迁移)。
Dave C

我不了解此dep功能,您的回答肯定可以帮助我:)
Veger

0

您可以使用命令go get -f来获取分叉的仓库

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.