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

970

我已经创建了一个带有子模块的git仓库。我可以告诉子模块自己如何更改其远程仓库路径,但是我不知道如何告诉父仓库如何更改子模块的远程仓库路径。

如果我需要手动操作的话,我并不会感到惊讶,因为即使删除子模块也不容易。


35
注:Git 2.25(2020年第一季度)推出了一个新命令git submodule set-url [--] <path> <newurl> - VonC
3
下面有一个答案链接,请点赞! - colan
9个回答

1277
你只需要编辑`.gitmodules`文件来更新URL,然后运行`git submodule sync --recursive`以反映该更改到超级项目和你的工作副本。然后,你需要进入`.git/modules/path_to_submodule`目录并更改它的配置文件以更新git路径。如果仓库历史不同,则需要手动checkout新分支。
git submodule sync --recursive
cd <submodule_dir> 

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

30
在1.7.1或1.7.3版本中,似乎这个操作无法更新.git/config文件。 - davidtbernal
7
这会更新之前提交的子模块 URL 配置吗?例如,如果我切换到旧的提交,它会指向新的子模块 URL 吗? - maxmelbin
76
使用命令 git submodule foreach -q git config remote.origin.url 查看“实际”的子模块 URL。 - Joel Purra
15
在使用Git 2.1.0时,它没有为我更新.git/config。在运行git submodule sync --recursive之前,我必须手动更新.gitmodules.git/config,以使我的子模块远程更新。 - desseim
21
似乎缺少关键的步骤 git submodule update --init --recursive --remote,这实际上会将仓库更改为新的远程地址。 - Jason Axelson
显示剩余10条评论

283

使用 Git 2.25(2020年第一季度),您可以修改它。
请参见“ Git 子模块 URL 已更改”和新命令。

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

(关于--分隔符,请参见“双短线作为停止选项解释的信号,将所有后续参数视为字面值”)

警告Hi-Angel评论中提到(即使在Git 2.31.1下进行了测试):

One should be careful with git submodule set-url because it has a bug:

If, inside your .gitmodules file, the path looks like this some-path, and then you execute a:

# Usually causes unexpected behavior
git submodule set-url some-path/ new-url

(note the trailing slash / in some-path/), then, instead of modifying existing submodule, the command will add another one. Instead run:

# Good
git submodule set-url some-path new-url

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

实际上,已经在2009年4月提交了一个补丁来澄清gitmodule的角色

因此,现在gitmodule文档还没有包括:

位于 Git 工作树顶层目录的 .gitmodules 文件是一个文本文件,其语法与 linkgit:git-config4 的要求相匹配。
[NEW]:
由于该文件由 Git 管理,因此它跟踪项目子模块的记录。
存储在该文件中的信息用作提示,以启动存储在项目配置文件中的记录的权威版本。
应将用户特定的记录更改(例如,为了解决由于网络情况而导致的子模块 URL 差异)应该在配置文件中进行,而应将要传播的记录更改(例如,由于子模块源的重定位)应该在此文件中进行。

这基本上证实了 Jim's answer


如果您遵循此git子模块教程,您会发现需要使用"git submodule init"将子模块存储库URL添加到.git/config中。
"git submodule sync"已于2008年8月添加,以使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 2.40(2023年第一季度)澄清了git config remote.<remote>.url

请参见提交记录 d390e08(2023年2月7日),作者为Calvin Wan(CalvinWan0101
(由Junio C Hamano -- gitster --提交记录 59397e9中合并,2023年2月15日)

文档:澄清多个pushurlsurls之间的区别

已签署:Calvin Wan

在具有多个配置URL的远程仓库中,git remote -v(man) 显示fetch使用的正确URL。
然而,git config remote.<remote>.url(man) 返回最后定义的URL,而不是第一个。
这种差异可能会导致对于具有此类定义的用户产生困惑,因为在第一个之后定义的任何URL实际上都充当了一个pushurl
添加文档以澄清如何使用多个URL进行fetch操作以及如何使用多个pushurls和urls进行push操作。

urls-remotes现在在其手册页面中包括:

<pushurl>仅用于推送。

它是可选的,默认为<URL>

向远程推送会影响所有定义的pushurls或所有定义的urls(如果未定义pushurls)。
但是,如果定义了多个URL,则仅从第一个定义的URL获取。


2
git submodule set-url [--] <path> <newurl> 中的可选双破折号有什么作用? - jeverling
2
@jeverling它们有助于将选项与参数分开:请参见https://dev59.com/iXM_5IYBdhLWcg3w3nRs#1192194 - VonC
1
现在应该选择这个答案。一个简单的命令搞定一切。 - Johannes
1
[--] 是什么意思?你能举个例子吗? - Harry
1
@M.Ionut 这就是我在 https://dev59.com/iXM_5IYBdhLWcg3w3nRs#1192194 中所描述/解释的。 - VonC
显示剩余6条评论

203

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

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
请查看博客中的截图:更改GIT子模块的URL /分支以使用同一存储库的其他URL /分支

11
这个方法可行,但我需要记得将更改推送到远程仓库。要完成操作,需要执行以下命令:git add .gitmodulesgit commit -m "修改子模块URL"以及git push origin master - skulz00
8
好吧,这给我带来了很大的麻烦。命令已经安静地执行了,但是实际的子模块仓库仍然认为它的远程仓库是旧的(旧的URL)。也许这些命令应该与子模块仓库内的其他命令一起执行? - Motti Shneor
7
最后一个命令有些过于极端了……如果你的子模块内还包含子模块,这个命令会同时远程更新子子模块,而这很可能不是你所需要的。 - Baptiste Wicht
12
请注意,您需要将"Submod"替换为您的子模块名称! - Shital Shah
1
这比手动进入您的.gitmodules文件要安全得多。谢谢 - MayTheSForceBeWithYou
回答有关子模块URL的其他问题,请参考以下链接:https://dev59.com/X1gQ5IYBdhLWcg3w6IOg#42035018。这是有关命令语义的有用描述。 - mmv-ru

166

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

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

git config --file=.gitmodules -e

或者只需:

vim .gitmodules

然后重新同步并更新:

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

12
git submodule update --init 对我有效,--remote 似乎将它绑定到远程仓库的 HEAD 上。 - Chaim Eliyah

88

以下是在Windows下,使用git版本1.8.3.msysgit.0的操作步骤:

  • 更新.gitmodules文件中与新仓库对应的URL
  • 从“.git/config”文件中删除相应行
  • 删除“.git/modules/external”目录中相应的子模块目录(对于最近的git版本,“.git/modules”)
  • 删除检出的子模块目录本身(不确定是否必要)
  • 运行“git submodule init”和“git submodule update”命令
  • 确保检出的子模块处于正确的提交状态,并提交该状态,因为哈希值可能会不同

完成上述所有操作后,一切都处于我所期望的状态。我想其他仓库的用户在更新时也会遇到类似的问题 - 在您的提交消息中解释这些步骤是明智的!


2
非常感谢您的帮助。在我已经运行了git submodule update之后,这是唯一有效的方法。按照其他答案的方法并不能更改./git/modules/external目录中的内容,因此尝试更新仍会导致它拉取错误的URL。 - NtscCobalt
1
这似乎有点危险,我不确定它是否保留了先前子模块的历史记录。例如,如果您想要检出主存储库(包含子模块)的旧提交或分支,我不确定它是否会知道拉取与该旧提交相关联的旧子模块。 - Motti Shneor
不,它几乎肯定不会知道 - 你将不得不再次执行第一步之后的所有步骤。这只是我发现用于清除子模块当前状态的方法。我不知道自从我写这篇文章以来事情的状态是否有所改变 :) - Ben Hymers
@MottiShneor 如果你需要保留之前的子模块历史记录,那似乎确实很危险,但我不确定。就我而言,这是唯一有效的解决方案,我想要的基本上是用我的分支替换原始子模块。 - arainone
2
按照这些步骤操作后,发现“删除已检出的子模块目录本身(不确定是否必要)”是必须的,否则在运行git submodule update时会遇到“fatal: Not a git repository: ...”错误。 - PiersyP

15

只需编辑您的.git/config文件。例如; 如果您有一个"common"子模块,您可以在超级模块中执行以下操作:

git config submodule.common.url /data/my_local_common

1
这只是最佳方式,如果您正在尝试为一次性使用更改URL,而不是在超级项目中永久更改。例如,您想要从磁盘上的本地副本克隆子模块。 - Andy

3

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


-2
一个暴力的方法:
  • 更新超级模块中的.gitmodules文件,使其指向新的子模块URL
  • 将更改添加并提交到supermodule/.gitmodules
  • 在计算机的其他位置创建超级模块的新克隆(确保克隆反映了.gitmodules文件的最新更改)
  • 将工作目录更改为超级模块的新克隆
  • 在子模块上运行git submodule update --init --remote path-to-submodule

好了!新克隆的超级模块中的子模块已被正确配置!


-4
很多人(无论是在这里还是在互联网上)建议的解决方案需要手动编辑或删除多个文件。但其实并不需要!
即使在 Git 2.25(以及 git submodule set-url < path > < newurl > 不可用的情况下),最简单的解决方案也是简单地“注销”子模块并使用新 URL 再次添加它。
根据 Git 版本和子模块设置,您可能需要手动删除

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