从 git 拉取后,子模块处于分离头状态



我在 Windows 8.1 上运行 git,并使用以下批处理脚本从上游拉取:

git pull --recurse-submodules
git submodule update --recursive --remote --init --merge
git submodule foreach "git pull || true"

我知道这是多余的,但是反复试验表明,有时上述任何一个命令都不会获取其他命令会获取的东西,因此在与它斗争了一段时间后,并在SO上阅读了不同的答案,我放弃了,采用了"皮带和吊带"方法。

这在大约一年的时间里工作得很好,直到一周前我更新到 git 版本 2.18.0.windows.1

从那时起,几乎每次调用都会导致某些子模块中的头部分离。 我进入有问题的分支,git checkout正确的分支,从子模块内部进行git pull,一切看起来都很好,但是如果我尝试在主存储库中再次运行脚本,BAM!相同的子模块进入分离的头部状态,即使上游没有任何更改并且没有被拉取。

我唯一知道更改的是 git 版本。

我做错了什么,正确的方式是什么?

编辑:

项目已设置,子模块用于在多个存储库之间共享的文件,并且开发人员会定期更改这些文件(不,我对此没有发言权(。

我试图完成的是在其签出分支上获取存储库的最新提交,然后更新超级项目指针并推送到源。

编辑 2:

以下内容会按照我上面的意图吗?

git pull
git submodule foreach "git pull || true"

子模块应该在任何时候都是分离的(尽管有一些特定的例外(。 如果他们以前不是,那就是问题所在。

请注意,git submodule update --remote --merge本质上等同于:

(cd $submodule; git checkout $superproject_hash; git fetch ${remote};
target_hash=$(git rev-parse $remote/$branch; git merge $target_hash)

那是:

  1. 确保子模块处于分离的 HEAD 模式,在超级项目命令的提交处。
  2. 从子模块的远程(通常是它的origin(获取,以便我们获得新的提交并更新$remote/$branch,其中$branch是超级项目中记录的分支。
  3. 发现更新的远程跟踪名称$remote/$branch的哈希 ID(由我们刚刚运行的抓取更新(。
  4. 在当前分离的HEAD上运行git merge,将当前HEAD快进到目标提交,或与目标提交进行真正的合并,从而产生新的提交。 无论哪种方式HEAD都保持分离,指向提交 - 如果我们进行了新提交,则为刚刚进行的新提交,或者如果我们能够快进,则指向目标提交。

编辑:你也可以使用不带--mergegit submodule update --remote,这基本上等同于:

(cd $submodule; git fetch $remote; git checkout $remote/$branch)

即,在使用git fetch更新远程跟踪名称后,将子模块的分离HEAD切换到当前的远程跟踪名称。 这可能更接近您的预期工作流程,但如果git merge使用快进,结果完全相同。


一般的想法是,子模块的提交哈希完全由超级项目和超级项目单独确定。 这要求它们处于分离 HEAD 模式。 在某些特定时间,您可能希望将子模块更新为其他提交;一旦你这样做了,那个提交,并且单独提交,是正确的提交,所以你将在超级项目中记录任何和所有新的哈希ID,子模块将在这些特定的提交上再次处于分离的HEAD模式,并且只有这些特定的提交 - 这继续要求它们处于分离的HEAD模式。

(有那么一刻,当你在子模块中,更新离开,你可能想暂时,在没有人在看,秘密地,短暂地,在分支上......但是,呜呜,让我们在任何人看到之前快速回到分离的 HEAD 模式! 这就是 Git 对子模块的态度。 如果你想在这个子模块中开发,好吧,Git 不会阻止你,但这只适用于闭门同意的成年人!

最新更新