如何获取所有分支 - 包括遥控器远程分支?

时间:2015-02-21 12:30:59

标签: git git-branch git-clone git-fetch

这里有几个赞成问题“如何获取所有远程分支”,而简短(upvoted)答案似乎是git clonegit fetch默认情况下应该这样做,而且可以通过运行git branch -r来查看远程分支。但是,我还是有点短暂。

我克隆了一个“上游”中央存储库,然后我再次克隆了这个克隆。比方说,我们在github上有存储库A,B是A的克隆,C是B的克隆。问题是C只包含B的本地分支。我想克隆/拉A - > B - > C,C具有A的所有分支。

我部分期待“你为什么要那样做?”在评论中。我认为考虑到git的分布式特性,它应该是可能的。但是,考虑带宽是昂贵的,存储库是巨大的,B和C生活在相同的文件系统或LAN上,并且大多数工作要在分支机构中完成 - 在这种情况下,不希望克隆A-> B并且A-> C,既不从A-> B和A-> C拉出,因为它意味着两倍的网络流量。还有其他原因,即防火墙不能从A-> C直接拉动。

2 个答案:

答案 0 :(得分:3)

您似乎无法(还)为远程配置多个默认refspec,但您可以在命令行中指定它们:

git fetch origin '+refs/heads/*:refs/remotes/origin/*' \
                 '+refs/remotes/*:refs/remotes/upstream/*'

这会将原点的远程跟踪分支的原点映射到远程跟踪分支到“上游”以及进行普通的提取。只要拥有这些分支就足够了,除非你有理由直接使用它,否则你不必定义远程。

要避免使用不熟悉的命令行,您可以使用原始网址和间接原点跟踪refspec定义upstream遥控器:

git remote add upstream `git config --get remote.origin.url`
git config remote.upstream.fetch '+refs/remotes/*:refs/remotes/upstream/*'

如果您还想使用单个命令进行两次提取,请添加

git config remotes.origin-all 'origin upstream'

然后

git fetch origin-all

在v2.2.2上进行测试:

~/sandbox/38$ ls -a
.  ..
~/sandbox/38$ git clone ~/src/git .
Cloning into '.'...
done.
~/sandbox/38$ git --version
git version 2.2.2
~/sandbox/38$ git remote add upstream `git config --get remote.origin.url`
~/sandbox/38$ git config remote.upstream.fetch '+refs/remotes/*:refs/remotes/upstream/*'
~/sandbox/38$ git config remotes.origin-all 'origin upstream'
~/sandbox/38$ git fetch origin-all
Fetching origin
Fetching upstream
From /home/jthill/src/git
 * [new ref]         origin/HEAD -> upstream/origin/HEAD
 * [new ref]         origin/maint -> upstream/origin/maint
 * [new ref]         origin/master -> upstream/origin/master
 * [new ref]         origin/next -> upstream/origin/next
 * [new ref]         origin/pu  -> upstream/origin/pu
 * [new ref]         origin/todo -> upstream/origin/todo
~/sandbox/38$ git checkout -b lala -t upstream/origin/master
Previous HEAD position was fdf96a2... Git 2.2.2
Branch lala set up to track remote ref refs/remotes/origin/master.
Switched to a new branch 'lala'
~/sandbox/38$ 

答案 1 :(得分:1)

一直想要类似的 - 保持工作或内部驱动器回购B和同一个远程回购A的USB备份驱动器回购C,而不是从A分别从A网重新获取。只有在开始写下我自己的问题之后才会出现这个问题的链接: How can I convert all the remote branches in a local git repo into local tracking branches 这可能对那些发现你的第二个解决方案更适合的人有用;像你一样,我也不喜欢它,它很乱。

阅读你的第一个解决方法让我思考并阅读git手册页 - git clone --mirror非常接近我们/我想要的,因为手册页说: Set up a mirror of the source repository. This implies --bare. Compared to --bare, --mirror not only maps local branches of the source to local branches of the target, it maps all refs (including remote-tracking branches, notes etc.) and sets up a refspec configuration such that all these refs are overwritten by a git remote update in the target repository.

所以git clone --mirror确实在本地克隆(某处)设置了我们需要的所有分支等,以便有效地制作其他本地克隆/ repos(例如B和C)。 “裸镜”中的“镜子”问题是它很乱;所以看来我们确实希望至少有一个裸露的回购“D”用于我们的“主镜像”,但使用git clone --mirror(而不是--bare)。

最后一个难题是让我们的“工作克隆”B尽可能多地共享这个“主要”回购D的objects/商店,因为它们位于相同的文件系统“装载空间” “(如果它们是)意味着你不能跨越装载点以使其起作用。

从头开始创建D(请参阅下面的链接以转换现有的回购):
git clone --mirror git://blah.com/A.git D.git

从D创建B:
git clone ../D.git/ B.git
并且git会自动做正确的事情 - 如果D和B没有越过安装障碍,则暗示git clone --local

不幸的是,这仍然需要两个步骤来更新“本地工作克隆”B,据我所知 - 在D中git fetch --all,然后是B中的git fetch --allgit pull。你可以当然,如果适合您选择的工作流程,请编写一个git-fetch包装器脚本来执行两个步骤。

在我的情况下,C也是一个--mirror回购(至少它将在大约5分钟后出现 - 它只是远程仓库的备份,换句话说,它是第二个“主镜” )。

Repo C可以配置为从B复制对象(不仅是D)。首先创建C,然后添加适当的遥控器,例如类似的东西:
从D创建C,作为镜像:
git clone --mirror blah://my.work.pc/my/mirrors/D.git C.git
或正常克隆:
git clone blah://my.work.pc/my/mirrors/D.git C.git
其次是:
git remote add B blah://my.work.pc/my/work/B.git
或者在您已经拥有C的特定情况下,只需将D添加为新遥控器。

然后,C上的git fetch --all应该从B和D中获取所有更新。

你可能需要How do I make existing non-bare repository bare?以及......

的一些魔法

从B创建D的另一种方法是使用类似的东西:
git clone --bare B.git D.git
结合How to change a git repository cloned with --bare to match one cloned with --mirror?的一些魔法 - 同时适当地更新D和当然B的遥控器。

请注意,git clone --local创建的硬链接会被git gc打破,这会自动发生。您可能更喜欢使用符号git链接的git clone -s ...,因此知道如何跨越本地文件系统“mount barrier”或git-new-workdir命令(在git repo的contrib / dir中 - 这只适用于非裸露的回购),这里都提到了:git as an alternative to unison。另请参阅Single working branch with Git和新Git 2.5 (Q2 2015) git checkout --to=path选项,以便对git-new-workdir及其最终git官方替换进行一些讨论。

为避免在使用git clone -s时出现意外,请务必阅读其工作原理,例如在man git-clone中,您可能需要按如下方式配置D(并阅读man git-prune):
git config gc.pruneExpire never

并且为了比较这两种方式,请参阅Brandon Casey在this discussion on git-new-workdir中的评论,即:

“如果你想要从中检出_multiple_different_分支 相同的存储库,并在所有存储库中进行开发,然后是git-new-workdir 是正确的选择。“

“如果你想在多个工作中签出_same_branch_ 目录,然后用-s克隆就是你想要的。在这种情况下 我假设开发将在原始仓库中执行,并且 克隆将进行更新。“

这表明clone -s可能仅对“测试”工作目录有用,而不适用于开发工作目录。

使用两个“本地主”回购,说D和C配置为每个作为另一个的远程和回购A,为奖励点编辑git配置文件并剪切并粘贴本地回购条目(例如D或C )将它移到远程(repo A)条目之上 - 这样git fetch --all通过首先在本地获取新的更改和分支(如果可能)来做正确的事情,而不必先手动获取本地存储,然后是A.现在,这是我为所有克隆的公共回购设置的设置,它是一种享受!

祝你好运。