克隆带有嵌套子模块的仓库无法正常工作。

4
我有多个独立的git存储库,其中没有子模块。任务是组装这些存储库的分层树,并将其用于用户之间的共享。使用“subtree”或“subrepo”方案很容易实现,但似乎无法使用“submodules”来实现。尝试使用子模块的原因是nfs系统上git的性能较慢。在我的情况下,检出需要超过2小时。
我正在尝试创建一个包含子模块的共享存储库。到目前为止,第一次克隆的尝试失败了。以下是测试用例:
 mkdir m1 ; cd m1 ; git init ; date > a.txt ; git add --all ; git commit -m added ; cd -
 mkdir m2 ; cd m2 ; git init ; date > b.txt ; git add --all ; git commit -m added ; cd -
 mkdir m3 ; cd m3 ; git init ; date > c.txt ; git add --all ; git commit -m added ; cd -
 mkdir msub; cd msub; git init; date > d.txt; git add --all; git commit -m added;
 git submodule add `realpath ../m1` m1
 cd m1
 git submodule add `realpath ../../m2` m2
 git submodule add `realpath ../../m3` m3
 git commit -m 'added submodules'
 cd ..
 git commit -m 'added a submodule'
 cd ..
 git clone --recursive msub msub1

作为结果,它创建了一个带有单个顶层子模块(m1)的msub1。
在其他情况下,在克隆第一个子模块后,我会收到类似于这样的致命错误。
fatal: git upload-pack: not our ref 89434ad65c1e697bfa311cd0260dfe1997985e65
fatal: remote error: upload-pack: not our ref 89434ad65c1e697bfa311cd0260dfe1997985e65
Fetched in submodule path 'soc', but it did not contain 89434ad65c1e697bfa311cd0260dfe1997985e65. Direct fetching of that commit failed.

我尝试直接向“m1”添加子模块,似乎改善了情况,但我不能在真正的存储库中这么做。

因此,所需方案似乎不起作用。有没有修复的方法呢?


我们很久以前就放弃了子模块,因为管理它们太痛苦了。在我看来,你可以通过提供一个包含一系列 git clone 命令的脚本来提供相同的功能,也许还可以单独选择。 - paxdiablo
@paxdiablo 谢谢,我尝试了一下,但觉得这个想法不太可靠。它必须依赖于分层的 .gitignores,并需要大量的脚本编写。对于庞大的客户群体来说,这样做效果不会很好。因此,我希望子模块能使其更易管理。 - Serge
2个回答

5
“非我们参考”的响应通常意味着你的服务器已配置为限制通过ID直接获取对象,并且没有适当的参考可以允许获取该对象。
Git提供了三个选项来控制是否可以获取任意对象ID:一个选项允许获取Git拥有访问权限的任何任意对象,一个选项允许获取从引用可达的任何对象,以及另一个选项允许获取从隐藏引用可达的对象。大多数服务器提供者选择禁用其中一个或多个选项,这通常意味着只有在一个非隐藏参考(即分支或标签)指向该对象时,才能请求对象ID。
“非我们参考”消息意味着你正在尝试按对象ID获取对象(用于子模块),但服务器由于上述原因不允许。如果你使用Bitbucket Server的ref缓存,则还可能意味着服务器已缓存过期数据;在这种情况下,如果需要使其正常工作,应禁用ref缓存。
你可以做一些事情。如果需要检出任意修订版本,可以创建指向它的分支。或者,如果你的子模块不需要特定版本,而只是分支的最新版本,可以设置submodule.<name>.branch选项(参见man gitmodules),然后永远检出最新的分支。如果使用自托管服务器,则可以将uploadpack.allowAnySHA1InWant设置为true。最后,你可以手动获取子模块(可能需要使用git submodule foreach),通常会有你想要的修订版本。

这一切都是在本地克隆操作中发生的,没有涉及可配置服务器。但我会尝试进行配置。谢谢。 - Serge

3
git submodule add `realpath ../m1` m1
cd m1
git submodule add `realpath ../../m2` m2
git submodule add `realpath ../../m3` m3

在这里,您修改了本地克隆的m1副本,但您没有将更改推回原始的m1

git commit -m 'added submodules'
cd ..
git commit -m 'added a submodule'

您忘记将子模块的变更添加到其中。

cd ..
git clone --recursive msub msub1

当git将msub克隆到msub1时,它会尝试从原始目录而不是msub / m1中克隆m1,这仅因为在顶级.gitmodules文件中存在指向原始m1的路径。而原始m1没有子模块。
为了修复整个工作流程,您需要:
- 在提交之前使用“ git add”更改了m1; - cd m1 && git push origin master(好吧,推送到非裸库不起作用,所以cd到原始库并pull)。
因此,整个修复脚本如下:
#! /bin/sh
set -e

mkdir m1 ; cd m1 ; git init ; date > a.txt ; git add --all ; git commit -m added ; cd -
mkdir m2 ; cd m2 ; git init ; date > b.txt ; git add --all ; git commit -m added ; cd -
mkdir m3 ; cd m3 ; git init ; date > c.txt ; git add --all ; git commit -m added ; cd -
mkdir msub; cd msub; git init; date > d.txt; git add --all; git commit -m added;
git submodule add `realpath ../m1` m1
cd m1
git submodule add `realpath ../../m2` m2
git submodule add `realpath ../../m3` m3
git commit -m 'added submodules'
cd ../../m1
git pull ../msub/m1 master
cd ../msub
git add m1
git commit -m 'added a submodule'
cd ..
git clone --recursive msub msub1

谢谢。我明白了。看起来子模块流违反了Git的哲学。它不会克隆已组装的存储库,而是克隆各个子模块的原始存储库,并在途中重建树形结构。除非在原始子模块存储库中推送,否则不会在其克隆中反映出原始树中子模块所做的任何提交。真遗憾! - Serge
.gitmodules 包含的是原始 URL,而不是本地克隆的 URL。这样的本地克隆通常根本没有公共 URL,因此将更改推送到原始 URL 是发布更改的唯一方法。如果您想克隆包含所有子存储库的整个存储库,请使用 git subtree - phd

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