如何获取所有分支 - 包括远程分支的远程分支?

3
这里有几个受欢迎的问题是“如何获取所有远程分支”,而短(受欢迎)的答案似乎是git clonegit fetch默认情况下应该可以做到这一点,可以通过运行git branch -r来查看远程分支。然而,我仍然有些困惑。
我已经克隆了一个“上游”中央存储库,然后我又克隆了这个克隆版本。 假设我们在github上有A存储库,B是A的一个克隆版本,C是B的一个克隆版本。 问题是C仅包含B本地的分支。 我想克隆/拉取A->B->C,并使C具有A的所有分支。
我部分期望在评论中会有“为什么要这样做?” 我认为,考虑到git的分布式特性,这应该是可能的。 但是,请考虑带宽成本很高,存储库非常大,B和C位于同一文件系统或局域网上,并且大部分工作都在分支中进行——在这种情况下,不希望将A->B和A->C克隆/拉取两次,因为这意味着两倍的网络流量。 还可能有其他原因,例如防火墙使直接从A->C拉取变得不可能。

我应该补充说明,我已经找到/考虑了两种解决方法 - 一种是进行完整的“git clone --mirror”,并让B和C从本地裸镜像库中拉取,另一种是在B上将远程分支作为本地分支进行检出和跟踪 - 但这感觉像是“愚蠢的解决方法”。 - tobixen
一年多过去了……我仍然在大多数本地代码库中将远程仓库设置为GitHub并直接从那里拉取代码,即使同一台笔记本电脑或智能手机上多次检出同一个代码库,偶尔我也会使用本地裸仓库镜像,标记为“local_mirror”,以免忘记将修改推送到GitHub。 - tobixen
2个回答

3

看起来你目前还不能配置一个远程仓库的多个默认Refspecs,请注意,你可以在命令行中指定它们:

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

这将把源remote的远程跟踪分支映射到你的"upstream"远程跟踪分支,同时进行常规获取。仅拥有这些分支就足够了,除非你有一些直接使用它的原因,否则不必定义remote。
为了避免不熟悉的命令行,您可以使用您的origin的url和间接-origin-tracking refspec来定义"upstream" remote。
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$ 

我似乎能够以这种方式拉取分支,并且可以通过完整名称检查它们并进入“分离的 HEAD 状态”,但我似乎无法跟踪这些分支。执行 git checkout -b somebranch --track upstream/origin/somebranch 后,会出现以下错误信息:fatal: Cannot setup tracking information; starting point 'upstream/origin/somebranch' is not a branch. - tobixen
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - jthill
git版本为2.2.2。尝试使用完全相同的命令:git checkout -b lala -t upstream/origin/master(存在主分支)。同样的错误。fatal: Cannot setup tracking information; starting point 'upstream/origin/master' is not a branch. 我正在测试一个“任意”的存储库,尽管我猜其他存储库的情况也是一样的。 - tobixen
我一有时间就会尝试使用不同版本的Git。 - tobixen
最近两天,我被一波技术小精灵袭击了。我的手机、两个网站和代码都出了问题。我完全理解你的感受。尝试在分支上使用全拼命令:-t refs/remotes/upstream/origin/master - jthill
显示剩余4条评论

1
我一直想要实现这样的功能——将工作或内部驱动器存储库B和USB备份驱动器存储库C与相同的远程存储库A同步,而不必为每个存储库单独从A重新获取。在开始撰写自己的问题之后,出现了与此问题相关的链接以及这个问题: 如何将本地git存储库中的所有远程分支转换为本地跟踪分支 对于发现第二种解决方法更可取的人可能会有用;像你一样,我也不喜欢那种方法,它很混乱。
阅读您的第一个解决方法让我思考并阅读了git手册 - git clone --mirror非常接近我们/我想要的内容,因为正如手册所说:
设置源存储库的镜像。这意味着--bare。与--bare相比,--mirror不仅将源的本地分支映射到目标的本地分支,还映射所有引用(包括远程跟踪分支、注释等),并设置一个refspec配置,使得在目标存储库中使用git remote update更新所有这些引用。

所以git clone --mirror会在本地克隆中设置所有所需的分支等,以便有效地创建其他本地克隆/仓库(例如B和C)。非裸露存储库中“镜像”的问题在于它很混乱;因此,我们似乎确实想要至少一个“主要镜像”裸仓库“D”,但使用git clone --mirror(而不是--bare)。

拼图的最后一块是使我们的“工作克隆”B尽可能共享此“主”仓库D的objects/存储库,因为它们位于同一文件系统“挂载空间”中(如果有的话),这意味着您不能跨越挂载点使其正常工作。

从头开始创建D(请参见下面的链接以将现有存储库转换为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 抓取所有更新。

您可能需要一些 如何将现有的非裸库变成裸库? 的技巧,以及...

另一种从 B 创建 D 的方法是使用以下命令:
git clone --bare B.git D.git
结合 如何将用 --bare 克隆的 git 存储库更改为与用 --mirror 克隆的存储库匹配的存储库? 中的一些技巧-同时适当地更新 D 和 B 的远程。

请注意,由git clone --local创建的硬链接会被git gc打破,后者会定期自动运行。您可以选择git clone -s ...,它使用符号git链接,因此知道如何跨越本地文件系统“挂载障碍”,或者使用git-new-workdir命令(在git repo的contrib / dir中 - 这仅适用于非裸体repo),这两个都在这里提到:git作为替代unison。另请参见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在git-new-workdir上的讨论中的评论,即:
“If you want to have _multiple_different_ branches checked out from the same repository, and do development in all of them, then git-new-workdir is the right choice.”
“If you want to have the _same_branch_ checked out in multiple work directories, then cloning with -s is what you want. In this case I assume development will be performed in the original repo, and the clones will do a pull to update.”
这表明clone -s可能仅适用于“测试”工作目录,而不适用于开发工作目录。

如果有两个“本地主”存储库,例如D和C,每个存储库都配置为另一个存储库和存储库A的远程,则可以编辑git配置文件并剪切粘贴本地存储库条目(例如D或C)以将其移动到远程(存储库A)条目上方 - 这样git fetch --all 就会正确获取新的更改和分支,首先在本地获取(在可能的情况下),而无需手动首先获取本地存储库,然后再获取存储库A。这是我所有克隆的公共存储库的设置,它非常有效!

祝好运。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接