英文:
Using forked package import in Go
问题
假设你在 github.com/someone/repo
上有一个存储库,并将其分叉到 github.com/you/repo
。你想使用你的分叉而不是主存储库,所以你执行以下操作:
go get github.com/you/repo
现在,该存储库中的所有导入路径都将“损坏”,这意味着,如果存储库中有多个包通过绝对URL相互引用,它们将引用源代码,而不是分叉。
是否有更好的方法,而不是手动将其克隆到正确的路径?
git clone git@github.com:you/repo.git $GOPATH/src/github.com/someone/repo
英文:
Suppose you have a repository at github.com/someone/repo
and you fork it to github.com/you/repo
. You want to use your fork instead of the main repo, so you do a
go get github.com/you/repo
Now all the import paths in this repo will be "broken", meaning, if there are multiple packages in the repository that reference each other via absolute URLs, they will reference the source, not the fork.
Is there a better way as cloning it manually into the right path?
git clone git@github.com:you/repo.git $GOPATH/src/github.com/someone/repo
答案1
得分: 171
如果您正在使用go modules,您可以使用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"
英文:
If you are using go modules. You could use replace
directive
> The replace
directive allows you to supply another import path that might
> be another module located in VCS (GitHub or elsewhere), or on your
> local filesystem with a relative or absolute file path. The new import
> path from the replace
directive is used without needing to update the
> import paths in the actual source code.
So you could do below in your go.mod file
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
where v3.2.1
is tag on your repo. Also can be done through CLI
go mod edit -replace="github.com/someone/repo@v0.0.0=github.com/you/repo@v1.1.1"
答案2
得分: 85
处理拉取请求
- 将一个仓库
github.com/someone/repo
fork 到github.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
英文:
To handle pull requests
- fork a repository
github.com/someone/repo
togithub.com/you/repo
- download original code:
go get github.com/someone/repo
- be there:
cd "$(go env GOPATH)/src"/github.com/someone/repo
- enable uploading to your fork:
git remote add myfork https://github.com/you/repo.git
- upload your changes to your repo:
git push myfork
http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html
To use a package in your project
答案3
得分: 21
一种解决方法是由Ivan Rave和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远程是awesome-you
。所有对于awesome-org
的导入都通过你刚创建的目录来解析,这是你的本地工作集。
更详细的信息,请参阅我的博客文章:在GitHub上分叉Golang存储库并管理导入路径
编辑:修正了目录路径
英文:
One way to solve it is that suggested by Ivan Rave and http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html -- the way of forking.
Another one is to workaround the golang behavior. When you go get
, golang lays out your directories under same name as in the repository URI, and this is where the trouble begins.
If, instead, you issue your own git clone
, you can clone your repository onto your filesystem on a path named after the original repository.
Assuming original repository is in github.com/awsome-org/tool
and you fork it onto github.com/awesome-you/tool
, you can:
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 is perfectly happy to continue with this repository and doesn't actually care some upper directory has the name awesome-org
while the git remote is awesome-you
. All import for awesome-org
are resovled via the directory you have just created, which is your local working set.
In more length, please see my blog post: Forking Golang repositories on GitHub and managing the import path
edit: fixed directory path
答案4
得分: 4
如果你的分支只是暂时的(即你打算合并它),那么只需在$GOPATH/src/launchpad.net/goamz
中进行开发。
然后,你可以使用版本控制系统的功能(例如git remote
)将上游仓库设置为你的仓库,而不是原始仓库。
这样做会使其他人使用go get
来使用你的仓库变得更困难,但更容易将其集成到上游仓库中。
实际上,我有一个用于goamz的仓库,位于lp:~nick-craig-wood/goamz/goamz
,我就是以这种方式进行开发的。也许作者有一天会合并它!
英文:
If your fork is only temporary (ie you intend that it be merged) then just do your development in situ, eg in $GOPATH/src/launchpad.net/goamz
.
You then use the features of the version control system (eg git remote
) to make the upstream repository your repository rather than the original one.
It makes it harder for other people to use your repository with go get
but much easier for it to be integrated upstream.
In fact I have a repository for goamz at lp:~nick-craig-wood/goamz/goamz
which I develop for in exactly that way. Maybe the author will merge it one day!
答案5
得分: 3
这是一个适用于所有人的方法:
使用github来fork到"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膨胀,保留了历史记录,并且构建工具可以理解它。
英文:
Here's a way to that works for everyone:
Use github to fork to "my/repo" (just an example):
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
Repeat each time when you make the code better:
git commit
git checkout enhancement
git cherry-pick <<commit_id>>
git checkout master
Why? This lets you have your repo that any go get
works with. It also lets you maintain & enhance a branch that's good for a pull request. It doesn't bloat git with "vendor", it preserves history, and build tools can make sense of it.
答案6
得分: 2
Instead of cloning to a specific location, you can clone wherever you want.
Then, you can run a command like this, to have Go refer to the local version:
go mod edit -replace github.com/owner/repo=../repo
https://golang.org/cmd/go#hdr-Module_maintenance
英文:
Instead of cloning to a specific location, you can clone wherever you want.
Then, you can run a command like this, to have Go refer to the local version:
go mod edit -replace github.com/owner/repo=../repo
答案7
得分: 1
答案是,如果你fork了一个包含多个包的仓库,你需要重命名所有相关的导入路径。这在很大程度上是一件好事,因为你已经fork了所有这些包,导入路径应该反映出这一点。
英文:
The answer to this is that if you fork a repo with multiple packages you will need to rename all the relevant import paths. This is largely a good thing since you've forked all of those packages and the import paths should reflect this.
答案8
得分: 0
使用vendoring和子模块一起
- 在github上fork库(在这个例子中是go-mssqldb)
- 添加一个子模块,将你的fork克隆到你的供应商文件夹中,但路径与上游库相同
- 在你的源代码中更新
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"
为什么
这解决了我在尝试自己弄清楚时遇到的所有问题。
- lib中的内部包引用现在可以工作,因为路径与上游库保持不变
- 项目的新检出可以工作,因为子模块系统会从正确的提交中获取你的fork,但在上游文件夹路径中
- 你不需要手动修改路径或者搞乱go工具。
更多信息
英文:
Use vendoring and submodules together
- Fork the lib on github (go-mssqldb in this case)
- Add a submodule which clones your fork into your vendor folder but has the path of the upstream repo
- Update your
import
statements in your source code to point to the vendor folder, (not including thevendor/
prefix). E.g.vendor/bob/lib
=>import "bob/lib"
E.g.
cd ~/go/src/github.com/myproj
mygithubuser=timabell
upstreamgithubuser=denisenkom
librepo=go-mssqldb
git submodule add "git@github.com:$mygithubuser/$librepo" "vendor/$upstreamgithubuser/$librepo"
Why
This solves all the problems I've heard about and come across while trying to figure this out myself.
- Internal package refs in the lib now work because the path is unchanged from upstream
- A fresh checkout of your project works because the submodule system gets it from your fork at the right commit but in the upstream folder path
- You don't have to know to manually hack the paths or mess with the go tooling.
More info
答案9
得分: 0
现代的解决方案(至少是 go 1.15 及更高版本)。
go mod init github.com/theirs/repo
使用明确的 init 参数来指定原始的包名。如果不包含仓库名称,它将假设在 GOPATH 中存在一个仓库。但是当你使用 go modules 时,它们不再关心它们在磁盘上的位置,或者 git 实际上从哪里拉取依赖项。
英文:
The modern answer (go 1.15 and higher, at least).
go mod init github.com/theirs/repo
Make an explicit init arg that is the ORIGINAL package names. If you don't include the repo name, it will assume the one in gopath. But when you use go modules, they no longer care where they are on disk, or where git actually pulls dependencies from.
答案10
得分: -1
为了自动化这个过程,我写了一个小脚本。你可以在我的博客上找到更多详细信息,以添加一个命令像"gofork"到你的bash。
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
英文:
To automate this process, I wrote a small script. You can find more details on my blog to add a command like "gofork" to your bash.
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
答案11
得分: -2
你可以使用命令 go get -f
来获取一个分叉的仓库。
英文:
You can use command go get -f
to get you a forked repo
答案12
得分: -3
在你的Gopkg.toml
文件中添加以下代码块:
[[constraint]]
name = "github.com/globalsign/mgo"
branch = "master"
source = "github.com/myfork/project2"
这样它将使用fork的project2
代替github.com/globalsign/mgo
。
英文:
in your Gopkg.toml
file add these block below
[[constraint]]
name = "github.com/globalsign/mgo"
branch = "master"
source = "github.com/myfork/project2"
So it will use the forked project2
in place of github.com/globalsign/mgo
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论