Git子模块推送

168

如果我修改了一个子模块,我能否将提交推送回子模块的远程仓库,还是需要克隆? 如果需要克隆,我可以将克隆存储在另一个仓库中吗?


11
使用git 2.7(2016年1月)版本,只需设置一次git config push.recurseSubmodules on-demand,然后简单的git push命令就足以推送所有内容(主库和子模块)。请参见下面我编辑的答案 - VonC
3个回答

182

子模块就是一个在另一个仓库中克隆git存储库的副本,带有一些额外的元数据(.gitmodules文件和gitlink树条目)

$ cd your_submodule
$ git checkout master
<hack,edit>
$ git commit -a -m "commit in submodule"
$ git push
$ cd ..
$ git add your_submodule
$ git commit -m "Updated submodule"

2
是的,不要忘记在推送之前从已同步的本地分支(如果有)拉取更改。例如,在使用github存储库上的gh-pages分支进行文档工作时会发生这种情况 :) - NiKo
1
我不明白为什么在添加子模块之前你可以使用“cd your_submodule”命令?我认为使用“add” git 命令是添加子模块的最佳方式。那么,还有其他方法可以添加子模块吗? - MrSo
3
@MrSo,我认为子模块已经存在了,他正在进入它以更改子模块中的某些内容。 - HattrickNZ
1
可以为所有子模块逐个迭代完成吗? - alper
2
@MrSo git add your_submodule 不会将子模块添加到项目中,因为子模块已经存在。将子模块添加到项目中的命令是:git submodule add [url]。他在这里做的只是将子模块上所做的更改从工作目录移动到暂存区。就像他处理其他更改一样(即 git add [filename/-A/.])。然后他可以提交更改。 - GG.
显示剩余2条评论

146
请注意,自git1.7.11([ANNOUNCE] Git 1.7.11.rc1release note,2012年6月)以来提到:

git push --recurse-submodules”学会了可选地查看绑定到超级项目的子模块的历史记录并将其推出。

可能是在this patch--on-demand选项之后完成的:

recurse-submodules=<check|on-demand>::

请确保远程跟踪分支上有所有子模块提交记录,这些提交记录将被用于推送的修订版本。

  • 如果使用了 check,则会检查在远程是否有所有子模块提交记录的更改。否则,推送将被中止并以非零状态退出。
  • 如果使用了 on-demand,则会推送所有在修订版本中更改的子模块。
    如果 on-demand 无法推送所有必要的修订版本,则也会中止并以非零状态退出。

因此,您可以通过以下方式一次性推送所有内容(从父存储库):

git push --recurse-submodules=on-demand

此选项仅适用于一层嵌套。在另一个子模块内部进行的子模块更改不会被推送。


使用git 2.7(2016年1月),简单的git push命令就足以推送父存储库和它所有的子模块。

查看commit d34141ccommit f5c7cd9(2015年12月3日),commit f5c7cd9(2015年12月3日)和commit b33a15b(2015年11月17日),作者为Mike Crowe (mikecrowe)
(由Junio C Hamano -- gitster --commit 5d35d72中合并,2015年12月21日)

push: 添加recurseSubmodules配置选项

--recurse-submodules 命令行参数已经存在一段时间了,但是没有相应的配置文件选项。

为了遵循与 git fetch 相对应的参数风格,我们发明了 push.recurseSubmodules 来为该参数提供默认值。
这也需要添加 --recurse-submodules=no 以允许在需要时通过命令行覆盖配置。

最直接的实现方式似乎是使 push 类似于 fetchsubmodule-config 中使用代码实现。

git config 文档现在包括

push.recurseSubmodules:

确保要推送的修订版本使用的所有子模块提交都可在远程跟踪分支上使用。

  • 如果值为'check',则Git将验证在至少一个子模块的远程中是否可用了所有更改的子模块提交。如果缺少任何提交,则推送将被中止并退出非零状态。
  • 如果值为'on-demand',则将推送在修订版本中更改的所有子模块。如果按需未能推送所有必要的修订版本,则它也将被中止并退出非零状态。
  • 如果值为'no',则保留推送时忽略子模块的默认行为。

您可以通过指定'--recurse-submodules=check|on-demand|no'来覆盖此配置。

git config push.recurseSubmodules on-demand
git push

Git 2.12 (2017年第一季度)

git push --dry-run --recurse-submodules=on-demand 实际上会起作用。

参见 commit 0301c82commit 1aa7365 (2016年11月17日),作者为 Brandon Williams (mbrandonw)
(由Junio C Hamano -- gitster --commit 12cf113中合并,2016年12月16日)

push run with --dry-run并没有在配置了按需推送子模块的情况下实际执行干运行(Git 2.11 Dec. 2016及更低版本/之前)。

相反,需要推送的所有子模块都会被推送到它们的远程仓库,而超级项目的任何更新都会以干运行的方式执行。

这是一个错误,不符合干运行的预期行为。

通过向执行干运行的子进程传递--dry-run标志来教会push在配置为按需递归推送子模块时尊重--dry-run选项。


在Git 2.12版本中,你现在可以使用"--recurse-submodules=only"选项将子模块推出而不推送顶层超级项目。

查看commit 225e8bf, commit 6c656c3, commit 14c01bd(2016年12月19日)由Brandon Williams (mbrandonw)提交。
(由Junio C Hamano -- gitster --合并于commit 792e22e,2017年1月31日)


在 Git 2.36 (2022年第二季度) 中, "git fetch --negotiate-only"(man) 是由 git push(man) 使用的内部命令,用于确定另一方缺少哪个部分的历史记录。
即使设置了 fetch.recursesubmodules 配置变量,它也不应递归到子模块中,也不应触发 "gc"。
代码已经被紧密地调整,以确保它只进行普通祖先发现,而不做其他任何事情。

查看 commit 386c076commit 135a12bcommit bec587d (2022年1月18日) 由 Glen Choo (chooglen) 提交。
查看 commit de4eaae (2022年1月20日) 由 Junio C Hamano (gitster) 提交。
(合并于 commit 472a219,2022年2月9日,由 Junio C Hamano -- gitster -- 完成)

fetch --negotiate-only: 不更新子模块

Signed-off-by: Glen Choo

git fetch --negotiate-only(man) 是推送协商的实现细节,与大多数 git fetch(man) 调用不同,它实际上不会更新主仓库。
因此,即使启用了子模块递归,也不应该更新子模块。

这不仅是慢的,而且是错误的,例如使用 "submodule.recurse=true" 进行推送协商将导致子模块被更新,因为它调用了 git fetch --negotiate-only

通过禁用子模块递归来修复此问题,如果给出了 --negotiate-only,则应禁用子模块递归。
由于这使得 --negotiate-only--recurse-submodules 不兼容,因此检查这种无效组合并退出。

fetch-options现在在man页面中包括以下内容:

这与--recurse-submodules=[yes|on-demand]不兼容。


使用 Git 2.39(2022年第四季度发布),可以通过 '--recurse-submodules=on-demand' 递归地推送所有子模块。
请参见 commit e62f779(由 Jonathan Tan (jhowtan) 于2022年11月14日提交)。
(由 Junio C Hamano -- gitster -- 合并于 commit 173fc54,2022年11月23日)

文档:文档 push.recurseSubmodules=only

署名: Jonathan Tan
署名: Taylor Blau

用户可以通过指定--recurse-submodules=only来学习推送子模块而不推送超级项目 6c656c3(“submodules:添加RECURSE_SUBMODULES_ONLY值”,2016年12月20日,Git v2.12.0-rc0-- batch #8中列出的merge)和225e8bf(“push:添加仅推送子模块选项”,2016年12月20日,Git v2.12.0-rc0-- batch #8中列出的merge)。
对于经常使用此功能的用户,希望有一个等效的配置。
事实证明,已经支持这样的配置(push.recurseSubmodules=only),尽管它既没有记录,也没有在提交消息中提到,因为--recurse-submodules=only特性的实现方式(用于解析--recurse-submodules的函数被更新以支持only,但是同样的函数也用于解析push.recurseSubmodules)。现在需要做的是记录并测试它,这就是这个提交所做的事情。
当递归到具有 push.recurseSubmodules=only 配置的子模块本身时,可能会有混淆点,因为如果仅将其子模块推送到存储库而不是自身,则其超级项目永远无法推送。因此,将这样的配置视为“按需”配置,并打印警告消息。
警告信息:
recursing into submodule with push.recurseSubmodules=only; using on-demand instead

git config现在包含在其man page中:

可能是“check”,“on-demand”,“only”或“no”,具有与“push --recurse-submodules”相同的行为。

git push现在包含在其man page中:

当使用“on-demand”或“only”时,如果子模块具有“push.recurseSubmodules={on-demand,only}”或“submodule.recurse”配置,则会发生进一步递归。在这种情况下,“only”被视为“on-demand”。


1
这现在可用,不是吗? - CMCDragonkai
1
@CMCDragonkai 是的,你可以在http://git-scm.com/docs/git-push中看到它。我已经编辑了答案。 - VonC
1
有递归提交吗? - CMCDragonkai
2
你可以随时执行 'git submodule foreach commit'。 - reflog
1
我必须使用Bitbucket的URL更新我的.gitmodules文件。 - wclark
显示剩余2条评论

4
你可以使用git的foreach命令
bash命令示例:
git submodule foreach "git add . && git commit -m 'update' && git push"

1
这个很棒。正在寻找它。 - Wim Pruiksma

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