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

时间:2018-09-08 01:00:00

标签: git git-detached-head

我正在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"

1 个答案:

答案 0 :(得分:2)

子模块被假定为可分离的,在任何时候都可以分离(尽管有一些特定的例外)。如果不是以前,那是错误的。

请注意,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. 在当前分离的git merge上运行HEAD,以将当前HEAD快进到目标提交,或与目标提交进行真正的合并,结果是新提交。不管哪种方式,HEAD都保持分离状态,指向提交-如果我们进行了新提交,则是刚刚提交的新提交;如果能够快速转发,则是目标提交。

编辑:您还可以使用git submodule update --remote --merge,这基本上等同于:

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

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


总体思路是,子模块的提交哈希完全由超级项目和超级项目单独确定。这就要求它们处于分离头模式。在某些特定时间,您可能需要将子模块更新为其他提交。一旦执行,该提交和单独的提交就是正确的提交,因此您将在超级项目中记录所有新的哈希ID,并且在这些特定的提交中,子模块将再次处于分离的HEAD模式,并且只有这些特定的提交-继续要求它们处于分离HEAD模式。

(有一段时间,您正在子模块中,更新时,您可能想要暂时地,而没有人偷偷地,短暂地在树枝上观看……但是,让我们回到分离状态-HEAD模式很快在任何人面前出现!这就是Git对子模块的态度。如果您想在该子模块中进行 develop ,那么Git不会阻止您,但这仅是为了让大人们闭门造车!)