如何在拉取后初始化新的子模块而不影响预先存在的子模块?

How do you initialize new submodules after a pull without affecting the pre-existing ones?

拉取后,我想用一个命令递归初始化所有新的子模块。

使用 git submodule update --init --recursive 的问题是它还会重置我先前存在的子模块指向的提交。

git submodule update --init --recursive 确实是用于递归初始化所有子模块的正确命令。将克隆子模块存储库,并检出记录在超级项目中的提交。

这在 git-submodule(1) 中正确记录:

Update the registered submodules to match what the superproject expects by cloning missing submodules, fetching missing commits in submodules and updating the working tree of the submodules. The "updating" can be done in several ways depending on command line options and the value of submodule.<name>.update configuration variable. The command line option takes precedence over the configuration variable. If neither is given, a checkout is performed. [...]

checkout: the commit recorded in the superproject will be checked out in the submodule on a detached HEAD.

[...]

If the submodule is not yet initialized, and you just want to use the setting as stored in .gitmodules, you can automatically initialize the submodule with the --init option.

If --recursive is specified, this command will recurse into the registered submodules, and update any nested submodules within.

请注意,您可以通过简单地使用 git clone --recurse-submodules.

获得相同的行为

我认为您必须编写脚本才能做到这一点。几乎所有 Git 命令都是以脚本形式开始的,并且仍然可以通过这种方式完成。

如果您始终保持所有子模块处于活动状态,那么 git submodule foreach --recursive 是您的起点,但是如果您选择检查哪些子模块,您将需要做的不仅仅是

git submodule foreach --recursive -q 'echo git -C $PWD checkout `git rev-parse @`'

(这实际上是 git submodule 文档中的示例)和 运行 打印的结帐以在递归更新做太多之后恢复您关心的内容。

现在你完全改变了你的问题并且你在问(强调我的):

After pulling, I would like to initialize all new submodules recursively with a single command.

The issue with using git submodule update --init --recursive is that it also resets which commit my pre-existing submodules are pointing to.

最好在此处提供更多详细信息,包括 MCVE(在 Git 问题的情况下,这通常意味着完整的 Git 命令集 运行,从git init/git clone开始)。如果不是,您的读者只能猜测您的确切情况(对于子模块,有很多可能性)。

要仅初始化新的子模块,您首先必须查明是否有您所做的 git pull 带来的任何新子模块。类似下面的内容应该列出自您在拉取 (ORIG_HEAD..) 之前进行的提交以来已添加 (--diff-filter=A) 的子模块 (grep 160000):

git log --format=%h ORIG_HEAD.. --summary --diff-filter=A | \grep 160000 | awk '{print }'

然后您可以将 git submodule update 与此子模块列表一起使用以仅初始化这些子模块:

git submodule update --init --recursive $(git log --format=%h ORIG_HEAD.. --summary --diff-filter=A | \grep 160000 | awk '{print }' | tr \n ' ')

请注意,从您的问题中不清楚您的 pre-existing 子模块处于什么状态,您希望避免更改的子模块。它们是“修改的”(即您在子模块中检出了一个不同的提交,但还没有在超级项目中 运行 git add),“添加”(即您在子模块中检出了一个不同的提交, 运行 git add 在超级项目中,但尚未在超级项目中提交该更改)或者相反,如果您的工作目录完全干净,但自上次拉取以来您确实提交了子模块更改。根据这一点以及您希望最终结果是什么样子,只需 运行ning git submodule update --init --recursive --mergegit submodule update --init --recursive --rebase 就可以满足您的需求...