移动 Git 子模块时,如何使用子模块的新 URL 更新父存储库中的完整历史记录?

问题描述

谁能帮帮我。 我想将一些 Git 存储库从一台服务器移动到另一台服务器,并同时重命名它们。 我遇到的问题是当某些存储库是其他存储库的子模块时。我想在顶级模块中所有分支的整个历史记录中替换子模块的 URL,这样一旦删除了原件,我仍然可以返回并重建旧的提交。 我使用的是 Windows PC,目前我正在使用 .bat 文件来运行我的存储库迁移。

要将子模块从 server1 移动到 server2 并将名称从 sub_old 更改为 sub_new 我将原始(裸)克隆到我的 C: 驱动器上的文件夹中,更改 URL,然后推送到新服务器:

git clone --bare https://server1/sub_old.git c:\temp_repo
cd c:\temp_repo
git remote set-url origin https://server2/sub_new.git
git push --mirror

然后从 server1 中删除 sub_old。

现在,当我想将使用 sub_old 存储库作为子模块的顶级存储库移动到新服务器时:

git clone --bare https://server1/top_old.git c:\temp_repo
cd c:\temp_repo
git remote set-url origin https://server2/top_new.git
REM At this point I want to change all of the references to the submodule from https://server1/sub_old.git to https://server2/sub_new.git
git push --mirror

然后从 server1 中删除 top_old。

在我想更改对子模块的所有 URL 引用时,我尝试使用:

git config --global url.https://server2/sub_new.git.insteadOf https://server1/sub_old.git

但没有成功。 我显然不明白这应该如何工作,或者它是否适合使用。

解决方法

我想在所有分支的历史记录中替换子模块的URL ...

这需要使用 git filter-branchgit filter-repo。从技术上讲,更改任何提交都是不可能的,因此这些命令不会这样做。相反,他们复制现有存储库的提交到一组全新的包含备用历史记录的提交。1

如果您选择这样做,请非常确定您想要,因为没有回头路。考虑使用新奇的 git filter-repo,它更擅长这类事情。2请记住,一旦完成,任何人都不应使用旧存储库或其任何克隆更多。把那些克隆人扔掉。改为创建 new 存储库的新克隆。

您使用的 git config 代替技巧有时是更好的方法。这不会替换整个历史中子模块的 URL!相反,这保留所有原始提交完整。这只是意味着对于——仅你的帐户,因为你使用了git config --global:没有其他用户受此影响——每当你的 Git 即将访问原始 URL 时,它就会切换改为替换 URL。

要使任何其他用户使用此功能,这些其他用户必须执行相同的 git config 步骤。如果这是一个问题,您需要“用新的存储库(代表替代历史的全新提交)替换存储库(所有提交,这是历史记录)”的方法。


1如果重写的“替代历史”从未重写的提交开始,则替代历史只是几乎全新的,而不是全新的。从某种意义上说,这更糟糕,因为它更容易意外地重新引入原始历史。那么你有两个历史,很难分辨哪一个是“真实”的。

2它似乎没有有针对性的“修复子模块 URL”选项,但这是一个合理的要求。在内部,这相当于过滤名为 .gitmodules 的文件,因此它应该很容易实现。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...