首页 > 解决方案 > 为什么 git 对子模块中的新提交视而不见?

问题描述

我在一个子模块中做了一个新的提交,但 git 并没有表明子模块在存储库的根级别上被更改(新提交)。

git status表示所有内容都是最新的,并不表示子模块中的更改(例如新提交)。

git commit --allow-empty也没有帮助。

标签: gitgit-submodules

解决方案


子模块只不过是另一个 Git 存储库,加上一些存储在超级项目中的链接。

通常,一个 Git 存储库从不知道其他 Git 存储库中的提交。有人可能认为超级项目中的链接可以使超级项目 Git 更加了解......有时,它可以,但不是你的情况。(我们不确切知道您的情况是什么,但显然,无论您的情况是什么,超级项目都不会立即注意到这些罕见的情况之一。)

如果一个 Git 存储库(我们将其称为S表示子模块)是某个其他 Git 存储库的克隆(我们将其称为OS表示子模块的起源),那么您可以进入存储库S并运行git fetch origin. 这会将来自OS的任何新提交带入S。没有新的提交在S中签出,因为除了存储库中的远程跟踪名称之外,永远不会更改任何内容。它只接受新的提交(然后适当地更新S等等)。git fetchorgin/master

如果您现在在存储库S中运行or ,您指定的提交将作为分离的 HEAD在S中签出。如果您运行,您指定的提交将作为附加的 HEAD 签出:S现在位于分支上。所有这一切的重要部分不是 HEAD 是附加还是分离。这是您检查了一些特定的提交1git checkout hash-idgit checkout non-branch-namegit checkout branch-name

当某个 Git 存储库(我们称之为R )正在使用某个其他存储库S作为子模块时,R中的各种操作将进入子模块S并运行,以在特定提交时将S置于分离的 HEAD 状态。此处使用的哈希 ID 记录在R中的提交中。git checkout hash

如果您自己输入Sgit checkout其他哈希 ID,然后返回R并询问其(R的)状态,处理R的 Git将注意到S不再处于R请求的提交上。因此它会说在S中发生了一些事情。您现在可以运行以更新R索引中的哈希 ID,以便它记录您在S中选择的提交的哈希 ID 。此时在R中进行新的提交会将新的哈希 ID 记录为正确的哈希 ID。git add path/to/S

签出R中的任何特定提交将使用来自该提交的子模块哈希 ID填充R的 Git 索引。除非您指定递归检出,否则这不会影响在S中作为分离头检出的哈希 ID ;您必须运行git submodule update以使R输入S并发出适当的命令。git checkout hash

如果您想自己手动控制S,这是做事的正确方法:您不希望R检查S中的内容并弄乱您的手动控制。如果您不想手动控制——如果您希望R始终控制S——请使用R中的--recursive结帐模式。


1虽然R通常使用分离的头,但超项目R 并不关心S的 HEAD是否附加。 无论如何,R都会记录一个原始的提交哈希 ID。所以它只是从S中读取哈希 ID ,而不是 branch-name-or-lack-thereof。


推荐阅读