克隆和子模块更新后,Git子模块处于“分离头”状态

时间:2013-12-27 04:55:18

标签: git

当我克隆我的git repo时,其中一个子模块位于一个带有奇怪名称的分支中,我认为这意味着它有一个“分离的头”(我甚至不确定那是什么装置)。

如果我签出子模块的主分支,则运行“git submodule update --init --recursive”它会再次发生。

有人知道发生了什么吗?

4 个答案:

答案 0 :(得分:36)

子模块总是作为分离的HEAD签出(参见“Why did git detach my head?”),因为父repo的索引仅包含SHA1作为special entry { {3}},正如in its indexGary Fixler所述。

即使您answer(或configure your submodule to follow a branch),git submodule update --remote也会检出该远程分支的最新SHA1,但结果仍然是独立的HEAD。

你需要进入那个子模块并在那里自己创建一个分支,如果你想为所述子模块做贡献(在其中进行新的提交)。

cd mySubmodule
git checkout -b aNewBranch
# work
git add .
git commit -m "new commits"
git push -u origin aNewBranch

# record the new submodule state in the parent repo:
cd ..
git add mySubmodule
git commit -m "new state of mySubmodule"
git push

Git 2.16(2018年第一季度)的注意事项:“git checkout --recursive”可能会覆盖和回退恰好在子模块中检出的分支的历史记录 存储库,这可能是不可取的。
分离HEAD但仍然允许递归结账在这种情况下成功。

参见convert an existing submodule to follow a branch(2017年7月28日)和commit 57f22bf(2017年7月24日)commit 3ef2538
Stefan Beller (stefanbeller)合并于Junio C Hamano -- gitster --,2017年12月6日)

  

递归子模块:从新状态分离HEAD

     

当子模块位于分支机构及其超级项目中时,运行一个   递归检出,子模块的分支更新为什么   超级项目检查出来   这在当前的Git模型中非常出乎意料,例如: 'submodule update'总是分离子模块HEAD。

     

尽管计划在未来将子模块HEADS拆开,   目前的行为非常糟糕,因为它与用户的期望不符   它不会检查是否有遗失(只能通过   引用日志)。

     

更新时,无条件地在子模块中分离HEAD。

答案 1 :(得分:15)

git目录的内容存储在名为“trees”的简单文本文件清单(即目录列表)中,如下所示,其中blob是文件的内容,而树木更像是这样的树:

100644 blob 0c31be662540ce902cee106f86bfdeef519fc662    .gitignore
100644 blob 1d364edf530c2238e79162bf2d9f30c2af610347    .gitmodules
040000 tree fc6bc39202ec20228e9135cd426110c558b625cd    foo
040000 tree 2f9fc460f3a2370ed45b39b2bcaaf9b6e746b823    bar

如果bar是子模块,而不仅仅是一个目录,则包含它的树将如下所示:

100644 blob 0c31be662540ce902cee106f86bfdeef519fc662    .gitignore
100644 blob 1d364edf530c2238e79162bf2d9f30c2af610347    .gitmodules
040000 tree fc6bc39202ec20228e9135cd426110c558b625cd    foo
040000 commit 2f9fc460f3a2370ed45b39b2bcaaf9b6e746b823  bar

请注意,不是bar是树,而是现在提交(在子模块中)。这是关于树/提交级别的子模块的所有git存储,因此它无法知道提交所在的分支。实际上,存储分支名称是行不通的。他们可以改变。另外,如果您检查回购中需要回滚子模块的旧提交,那么分支是否应该移回子模块中?这会将新分支位置之后的提交转换为未引用的区域。

这些分支是供人类使用,以理解DAG,以及特定的思路。 Git并不关心我们如何引用提交。它需要一个具体的位置,以便您可以安全地移动包含的repo,并且知道子模块将始终检出它当时的位置。唯一的事实是哈希。

答案 2 :(得分:2)

对于Sourcetree的用户 - 您将观察到相同的行为 - 克隆将为您提供处于分离状态的子模块。正如VonC提到in his answer,如果您想要为子模块做出贡献,则需要执行一些额外的步骤。

除了从子模块SHA-1创建一个新分支外,在大多数情况下,您只需要检查现有分支的头部。除非将子模块配置为遵循特定分支,否则这将是主。

您可以打开每个子模块并手动签出相应的分支,也可以创建自定义操作来为您执行此操作(递归!):

enter image description here

要运行的脚本

cmd

参数

/c %LOCALAPPDATA%\Atlassian\SourceTree\git_local\bin\sh.exe --login -i -c "git pull; git submodule foreach -q --recursive 'toplevel=\"$(git rev-parse --show-toplevel)\"; branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; [ \"$branch\" = \"\" ] && branch=master; git checkout $branch; git fetch; git merge FETCH_HEAD;'"""

这将检查项目中的所有子模块并检查他们指向的分支(如果他们没有指定分支,则检查它们)。它是递归的,因此任何包含子模块的子模块也将被处理。

正如我在an earlier post中发现的那样,最后需要额外的一对引号。

答案 3 :(得分:1)

branch中添加 .gitmodule选项 与子模块的分离行为完全无关

git submodule --help中,默认行为是git submodule update --remote 断开。

首先,无需指定要跟踪的分支origin/master是要跟踪的默认分支。

  

-远程

     

代替使用超级项目的记录的SHA-1更新子模块,而要使用子模块的远程跟踪分支的状态。使用的遥控器是分支机构的遥控器(branch.<name>.remote),默认为origin 。远程分支使用的默认值为master

为什么

那为什么在update之后分离HEAD?因为submodule.$name.update默认行为是checkout

  

-结帐

     

在子模块中的分离的HEAD 上签出超级项目中记录的提交。这是默认行为,此选项的主要用途是在设置为submodule.$name.update以外的值时覆盖checkout

如何

如果您希望子模块自动与远程分支合并,请使用--merge--rebase

  

-合并

     

此选项仅对更新命令有效。将超级项目中记录的提交合并到子模块的当前分支中。如果指定了此选项,则子模块的HEAD将不分离

     

-重新设置

     

将当前分支重新基于超级项目中记录的提交。如果指定了此选项,则子模块的HEAD将不分离

您需要做的就是

git submodule update --remote --merge
# or
git submodule update --remote --rebase

通过将--merge设置为--rebasegit submodule update,还可以选择将submodule.$name.updatemerge设置为rebase的默认行为

这是一个有关如何在.gitmodule中配置子模块更新的默认更新行为的示例。

[submodule "bash/plugins/dircolors-solarized"]
    path = bash/plugins/dircolors-solarized
    url = https://github.com/seebi/dircolors-solarized.git
    update = merge # <-- this is what you need to add

我的全部答案都基于手册。 git submodule --help