如何更改 git 子模块的远程存储库?

Posted

技术标签:

【中文标题】如何更改 git 子模块的远程存储库?【英文标题】:How to change the remote repository for a git submodule? 【发布时间】:2010-10-29 03:51:23 【问题描述】:

我创建了一个带有子模块的 git 存储库。我能够告诉子模块本身更改其远程存储库路径,但我不确定如何告诉父存储库如何更改子模块的远程存储库路径。

如果我有些运气不佳并且不得不手动执行操作,我不会感到惊讶,因为即使删除子模块也不容易。

【问题讨论】:

注意:Git 2.25 (Q1 2020) 自带a new command": git submodule set-url [--] <path> <newurl> below 有答案。请点赞! 【参考方案1】:

您应该能够编辑 .gitmodules 文件以更新 URL,然后运行 ​​git submodule sync --recursive 以将该更改反映到超级项目和您的工作副本。

然后你需要转到.git/modules/path_to_submodule 目录并更改其配置文件以更新 git 路径。

如果回购历史不同,那么您需要手动签出新分支:

git submodule sync --recursive
cd <submodule_dir> 

git fetch
git checkout origin/master
git branch master -f
git checkout master

【讨论】:

这似乎没有更新 .git/config,至少在 1.7.1 或 1.7.3 中。 这是否也会更新先前提交的子模块 url 配置?例如,如果我签出一个较旧的提交,它会指向新的子模块网址吗? 使用git submodule foreach -q git config remote.origin.url查看“实际”子模块网址 它没有为我使用 git 2.1.0 更新 .git/config。在运行git submodule sync --recursive 之前,我必须手动更新.gitmodules.git/config 才能更新我的子模块远程。 这似乎缺少git submodule update --init --recursive --remote 的关键步骤,它实际上将存储库更改为新的远程【参考方案2】:

使用 Git 2.25(2020 年第一季度),您可以修改它。 请参阅“Git submodule url changed”和新命令

git submodule set-url [--] <path> <newurl>

(在-- 分隔符上,请参阅“double hyphen as a signal to stop option interpretation and treat all following arguments literally”)

警告:Hi-Angel 提到 in the comments(即使使用 Git 2.31.1 也已测试):

人们应该小心git submodule set-url,因为它有一个错误:

如果在您的.gitmodules 文件中,路径看起来像这样some-path,然后您执行git submodule set-url some-path/ new-url(注意尾部斜杠/),那么,该命令不会修改现有的子模块,而是添加另一个。


原始答案(2009 年 5 月,十年前)

其实是一个补丁has been submitted in April 2009来澄清gitmodule的作用。

所以现在gitmodule documentation 还不包括:

.gitmodules 文件位于 git 工作树的***目录中,是一个文本文件,其语法符合要求 -of linkgit:git-config4。 [新]: 由于此文件由 Git 管理,因此它跟踪项目子模块的 +records。 此文件中存储的信息用作提示,以启动项目配置文件中存储的记录的权威版本。 应该对配置文件进行用户特定的记录更改(例如,考虑到由于网络情况导致的子模块 URL 的差异),同时应该进行传播的记录更改(例如,+由于子模块源的重定位)到这个文件。

这几乎证实了Jim's answer。


如果您关注此git submodule tutorial,您会看到需要“git submodule init”来将子模块存储库 URL 添加到 .git/config。

"git submodule sync" 具有 been added in August 2008 正是为了在 URL 更改时使该任务更容易(尤其是在子模块的数量很重要的情况下)。 该命令的关联脚本非常简单:

module_list "$@" |
while read mode sha1 stage path
do
    name=$(module_name "$path")
    url=$(git config -f .gitmodules --get submodule."$name".url)
    if test -e "$path"/.git
    then
    (
        unset GIT_DIR
        cd "$path"
        remote=$(get_default_remote)
        say "Synchronizing submodule url for '$name'"
        git config remote."$remote".url "$url"
    )
    fi
done

目标依然:git config remote."$remote".url "$url"

【讨论】:

git submodule set-url [--] &lt;path&gt; &lt;newurl&gt; 中可选的双破折号有什么作用? @jeverling 它们有助于将选项与参数分开:参见***.com/a/1192194/6309 请注意,对于使用旧版本 git 的 Ubuntu 用户,您可以使用此 PPA 进行更新:launchpad.net/~git-core/+archive/ubuntu/ppa 这应该是现在的首选答案。一个简单的命令就可以搞定一切。 [--] 是什么意思?能举个例子吗?【参考方案3】:

只需编辑您的 .git/config 文件。例如;如果你有一个 "common" 子模块,你可以在超级模块中这样做:

git config submodule.common.url /data/my_local_common

【讨论】:

如果您尝试更改 URL 以供一次性使用,而不是永久用于超级项目,这只是最好的方法。例如。你想从磁盘上的本地副本克隆子模块。【参考方案4】:

什么对我有用(在 Windows 上,使用 git 版本 1.8.3.msysgit.0):

使用新存储库的 URL 更新 .gitmodules 从“.git/config”文件中删除对应的行 删除“.git/modules/external”目录下的对应目录(最新的git版本为“.git/modules”) 删除签出的子模块目录本身(不确定是否有必要) 运行git submodule initgit submodule update 确保签出的子模块处于正确的提交位置,然后提交,因为哈希可能会有所不同

完成所有这些之后,一切都处于我所期望的状态。我想存储库的其他用户在更新时也会有类似的痛苦 - 在您的提交消息中解释这些步骤是明智的!

【讨论】:

非常感谢您。在我已经运行了git submodule update 之后,这是唯一对我有用的。遵循其他答案不会改变 ./git/modules/external 目录中的内容,因此尝试更新会导致它仍然拉取不正确的 url。 这似乎有点危险,我不确定它是否保留了前一个子模块的历史。例如,如果您想检查主存储库的旧提交或分支(包含子模块的那个),我不确定它是否会知道拉出与主存储库的旧提交相关的旧子模块. 不,它几乎肯定不会知道 - 您必须在第一个步骤之后再次执行所有步骤。这正是我发现对子模块当前状态起作用的方法。我不知道自从我写这篇文章后情况是否发生了变化,请注意:) @MottiShneor 如果您需要保留以前的子模块历史记录,这似乎确实很危险,尽管我不确定。就我而言,这是唯一可行的解​​决方案,我想要的基本上是用我自己的 fork 替换原来的子模块 按照这些步骤,发现“删除签出的子模块目录本身(不确定是否有必要)”是必要的,否则你会遇到“致命:不是git存储库:...”时运行 git 子模块更新【参考方案5】:

这些命令将在命令提示符下完成工作,而不会更改本地存储库中的任何文件

git config --file=.gitmodules submodule.Submod.url https://github.com/username/ABC.git
git config --file=.gitmodules submodule.Submod.branch Development
git submodule sync
git submodule update --init --recursive --remote

截图请看博文:Changing GIT submodules URL/Branch to other URL/branch of same repository

【讨论】:

这行得通,但我必须记住将更改推送到遥控器。 git add .gitmodulesgit commit -m "modified submodule URL"git push origin master 好吧,这给我造成了可怕的混乱。命令安静下来,但实际的子模块存储库仍然认为它的远程是旧的(旧的 URL)。也许这些命令应该与子模块存储库中的其他命令一起使用? 最后一个命令有点极端……如果你的子模块里面有子模块,这也会远程更新子子模块,这不太可能是你需要的。 请注意,您需要将 Submod 替换为子模块的名称! 这比手动进入你的 .gitmodules 文件风险小。谢谢?【参考方案6】:

git config --file=.gitmodules -e 打开默认编辑器,您可以在其中更新路径

【讨论】:

【参考方案7】:

简单来说,你只需要编辑 .gitmodules 文件,然后重新同步更新即可:

通过 git 命令或直接编辑文件:

git config --file=.gitmodules -e

或者只是:

vim .gitmodules

然后重新同步并更新:

git submodule sync
git submodule update --init --recursive --remote

【讨论】:

git submodule update --init 为我工作,--remote 似乎将它与远程仓库的 HEAD 联系在一起。【参考方案8】:

蛮力方法:

更新超级模块中的.gitmodules 文件以指向新的子模块url, 将更改添加并提交到supermodule/.gitmodules, 在您计算机的其他位置创建超级模块的新克隆(确保对 .gitmodules 文件的最新更改反映在克隆中), 将您的工作目录更改为超级模块的新克隆, 在子模块上运行git submodule update --init --remote path-to-submodule

等等!超级模块的新克隆中的子模块配置正确!

【讨论】:

【参考方案9】:

很多人(包括这里和整个互联网)都提出了需要手动编辑或删除多个文件的解决方案。但这真的不需要!

即使在 Git 2.25(因此 git submodule set-url &lt;path&gt; &lt;newurl&gt;)不可用的环境中,最简单的解决方案是简单地“取消注册”子模块并使用新 URL 再次添加它。

根据 Git 版本和子模块设置,您可能需要在再次添加之前手动删除 &lt;path&gt;。无需其他手动操作!

git submodule deinit <path>
rm -rf <path>
git submodule add <repository> [<path>]

之后,.gitmodules 文件将具有不同的 URL,应提交。所有其他地方(配置、工作树)都已由 git 处理。

为了解释 deinit 的作用,我想引用 Git 手册:

deinit [-f|--force] (--all|[--] &lt;path&gt;…​)

取消注册给定的子模块,即从 .git/config 中删除整个 submodule.$name 部分及其工作树。进一步的调用 [..] 将跳过任何未注册的子模块,直到它们再次被初始化

【讨论】:

以上是关于如何更改 git 子模块的远程存储库?的主要内容,如果未能解决你的问题,请参考以下文章

Git子模块与依赖管理?

Git:在分支中创建子模块

Git修改子模块的路径

如何`git submodule add`现有的子存储库?

如何将 git 子模块与 Bitbucket 管道一起使用?

替代git子模块