Git 子模块对其远程存储库的引用有误

Git Submodule has a wrong reference to its remote repository

我的主存储库中有两个子模块,它们都链接到另外两个远程存储库。

我想我以某种方式设法将我的第二个子模块放在其他分支或类似的地方。
长话短说,我什至无法再克隆主代表 (git clone --recursive-submodules),因为第二个子模块的 ID 错误,无法链接到其远程代表。
我收到“error: no ref to the remote rep”。

有人可以帮助我吗?
如何更改子模块的 ID?
或者我需要取回主分支上的第二个子模块吗?

TL;DR:我认为你得到的是我在下面提到的你没有推送 submodule 提交的情况。所以现在当超级项目从超级项目克隆的子模块中获取一个特定的提交时,它(超级项目Git)找不到它(子模块中所需的提交)。

背景

子模块很痛苦,因为每个子模块本身 一个 Git 存储库这一事实与每个 "superproject"(控制一个子模块)坚持知道哪个提交子模块必须使用。

当您的所有子模块都是由其他人维护的外部库时,这一切都很好。您编写了一些需要库 A、B 和 C 的代码。您使用 A 中的 "commit 1234567"、B 中的 "commit 8888888" 和 C 中的 "commit fedcba9" 对其进行测试,一切正常...所以你决定这个版本的代码应该永远使用这三个子模块的三个提交。

您只需在超级项目中提交即可。每个提交记录,始终准确地哪个提交子模块必须

然后,每当您签出超级项目时,您都会告诉您的超级项目 Git 去干预每个子存储库并分离其 HEAD。这就是 为什么 你看到 "detached at" 或 "detached from"。 "at" 或 "from" 部分 完全不相关 在这一点上:不要注意它!当您在 那些库上工作时,这意味着您的信息,并且因为您实际上正在处理超级项目,所以您的超级项目 Git 假设您是 处理它们。

但有一个问题:如果您想要处理它们怎么办?你的超级项目 Git 对着你尖叫,不不不,你不能碰它们!我控制他们! :-) 好吧,它不是 相当那么糟糕,但是......它很糟糕。

要在存储库中工作,您通常希望在分支上。所以你必须进入子模块并撤消你的超级项目Git所做的,通过检查一些特定的分支。现在您可以正常处理子模块了。

但这会让您的超级项目感到不安 Git。此外,您无法真正 测试 它,直到您将所有内容都重新排好。您必须输入所有子模块,将它们拉回到 "branch-y" 模式,在其中工作,可能单独测试它们,甚至可能进行提交。现在你可以回到你的超级项目......但是你还不能在那里提交,因为他们仍然记得 old detached-HEAD hashes!

使所有内容重新排列的唯一方法是实际在子模块中进行提交。现在每个子模块都有一个 new 哈希 ID,每个子模块的 Git 在您在那里进行提交时分配。你现在可以爬回你的超级项目并告诉 that Git: "I'm ready to commit, but before I do, here are your new hash IDs." 你通过再次 git add-ing 每个子模块来做到这一点,这使得你的超级项目 Git 去读出子模块哈希并将它们放入你的超级项目的索引中。 现在您可以在超级项目中git commit,它将永久地、永远地记录新的提交,因为每个子模块都使用新的哈希值。

请注意,如果您现在推送超级项目,其他所有人都会遇到问题:您在子模块中所做的新提交在您的 子模块存储库,但这些提交尚未被推回到它们可能去的任何地方。任何获取你的新超级项目提交的人都会得到一个写着 "submodule A shall use commit feedcab" 的提交,但他们不能 get 提交 feedcab 直到你推送 that也是。所以必须先push所有的子模块,然后才push superproject

这一切都有效,但请注意这个过程是多么脆弱。 Git 的子模块随着时间的推移变得更好,因为您现在实际上可以告诉控制 Git 的超级项目(递归地)下降到每个子模块 Git 并将 在一个分支(其分支名称记录在超级项目中)。这就解决了第一个问题。

如果您不是 控制 子模块远程存储库的人,您会遇到一系列不同的问题。 git submodule update 命令增加了一大堆额外的选项来尝试适应这些情况。 git submodule foreach 命令允许您在每个子模块中 运行 任何内容 (例如您自己的脚本),这使您可以完全控制,但代价是让您编写,好吧,完全控制。但是子模块的情况仍然相当混乱,许多组织试图避免它们(我自己会,并且会这样做)。

How can I change the ID of a submodule?

在你的情况下,你不能克隆你的子模块仓库,因为它的 gitlink, (special entry in the index of the parent repo) 引用了一个 not 推送到远程仓库的 SHA1所述子模块。

由于您没有子模块文件夹内容(无法签出),您不能简单地从所述子模块添加、推送和提交。

为了完成克隆,最好将关联的gitlink SHA1 更改为之前的版本:

git checkout $(git log -1 --format=format:%H yoursubmodule) -- yoursubmodule

yoursubmodule 替换为代表您的子模块的文件夹的名称,不带尾部斜杠(因为它是索引中的条目,而不是文件夹)

然后一个git submodule update --init应该足以初始化该子模块内容。

最后,查看“Git submodules: Specify a branch/tag”,并将您的子模块关联到一个分支:

git config -f .gitmodules submodule.<path>.branch <branch>

这样,下次 git submodule update --remote 就足以将您的子模块更新到该分支的最新远程 SHA1。