如何递归地检出包括所有子模块在内的旧git提交?

71
我有一个包含多个子模块的git仓库。其中一个子模块又有多个自己的子模块。我想要做的只是在主仓库上检出一个旧的提交,并使它检出所有子模块的适当提交,以获取该时刻代码的正确状态。
我知道git包含必要的信息,因为ls-tree命令可以告诉我每个子模块在哪个提交上。然而,我必须手动检出每一个子模块,这非常耗时。
我正在寻找类似于“git checkout --recursive”的东西,但这样的命令似乎不存在。
有没有办法做到这一点?

4
注意:git checkout --recurse-submodules 现在已经存在(2017年)。但是只有即将发布的 Git 2.14 才能使其正常工作。请参见 下面我的答案 - VonC
3个回答

66
你需要两个命令来实现这个目标:
git checkout *oldcommit*
git submodule update --recursive

更新:截至2018年,此答案已过时-请参见VonC下面的答案获取更多当前信息。


2
非常感谢!当然,结果证明这只是一些简单的东西。 - Ben Baron
1
有人能澄清一下 checkout --recurse-submodulessubmodule update --recursive 之间的区别吗? - Lii
这个有没有一行代码的等效写法? - Eduardo Pignatelli
我发现使用von c的答案时,它没有正确地检出所有子模块,git状态显示了修改。而使用你的答案,它确实正确地更新了整个树。git v2.24.3 - openCivilisation

56
注意:如果您有多个子模块(以及子模块内的子模块),Git 2.14(2017年第三季度)将提供帮助(比2013年的OP更新)。
git checkout --recurse-submodules

使用--recurse-submodules将根据超级项目中记录的提交更新所有已初始化子模块的内容。如果子模块中存在本地修改,而这些修改将被覆盖,则必须使用-f才能执行检出操作,否则检出将失败。 "git checkout --recurse-submodules" 在具有子模块的子模块中并不完全适用。它将在Git 2.14中适用。
注意:从Git 2.19(2018年第三季度)开始,git checkout --recurse-submodules another-branch更加健壮。
在此之前,它没有报告更新工作树失败的子模块,导致出现无用的错误消息。

请参见提交ba95d4e(2018年6月20日),作者为Stefan Beller(stefanbeller
(由Junio C Hamano -- gitster --提交392b3dd中合并,2018年7月24日)

submodule.c: report the submodule that an error occurs in

When an error occurs in updating the working tree of a submodule in submodule_move_head, tell the user which submodule the error occurred in.

The call to read-tree contains a super-prefix, such that the read-tree will correctly report any path related issues, but some error messages do not contain a path, for example:

~/gerrit$ git checkout --recurse-submodules origin/master
~/gerrit$ fatal: failed to unpack tree object 07672f31880ba80300b38492df9d0acfcd6ee00a

Give the hint which submodule has a problem.


我不明白为什么-f总是必要的。没有-f,它就不会更新子模块。 - linquize
@linquize 只有在子模块中有本地修改时,才需要使用“-f”。 - VonC
有人能澄清一下 checkout --recurse-submodulessubmodule update --recursive 之间的区别吗? - Lii
@Lii 子模块更新部分(https://git-scm.com/docs/git-submodule#Documentation/git-submodule.txt-update--init--remote-N--no-fetch--no-recommend-shallow-f--force--checkout--rebase--merge--referenceltrepositorygt--depthltdepthgt--recursive--jobsltngt--ltpathgt82308203)将使用配置项`submodule.<name>.update(https://git-scm.com/docs/git-config#Documentation/git-config.txt-submoduleltnamegtupdate)。而git checkout --recurse-submodule`则不会。 - VonC
@Lii 另一个区别是:checkout --recurse-submodule 会更新您的父存储库和子模块,而 submodule update --recursive 仅会影响子模块的工作树,不会更新父工作树。 - VonC

18

根据旧的检出中是否有更多的子模块,您可能需要执行以下操作来初始化在新提交中不存在的子模块:

git checkout *oldcommit*
git submodule init
git submodule update --recursive

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