当我克隆我的git repo时,其中一个子模块位于一个带有奇怪名称的分支中,我认为这意味着它有一个“分离的头”(我甚至不确定那是什么装置)。
如果我签出子模块的主分支,则运行“git submodule update --init --recursive
”它会再次发生。
有人知道发生了什么吗?
答案 0 :(得分:36)
子模块总是作为分离的HEAD签出(参见“Why did git detach my head?”),因为父repo的索引仅包含SHA1作为special entry { {3}},正如in its index的Gary 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创建一个新分支外,在大多数情况下,您只需要检查现有分支的头部。除非将子模块配置为遵循特定分支,否则这将是主。
您可以打开每个子模块并手动签出相应的分支,也可以创建自定义操作来为您执行此操作(递归!):
要运行的脚本
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
设置为--rebase
或git submodule update
,还可以选择将submodule.$name.update
或merge
设置为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
。