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

eqzww0vc  于 2023-01-19  发布在  Git
关注(0)|答案(5)|浏览(237)

当我克隆我的git repo时,其中一个子模块在一个名字奇怪的分支中,我认为这意味着它有一个“detached head”(我甚至不确定这是什么意思)。
如果我 checkout 子模块的主分支,然后运行“git submodule update --init --recursive“,它会再次发生。
有人知道发生什么事了吗?

eni9jsuy

eni9jsuy1#

子模块 * 总是 * 作为分离的HEAD checkout (参见“Why did git detach my head?“),因为父存储库的索引只包含SHA1作为special entryin its index,如Gary Fixleranswer所解释的。
即使您使用configure your submodule to follow a branch(或convert an existing submodule to follow a branch),git submodule update --remote也会检出该远程分支的最新SHA1,但结果 * 默认情况下 * 是一个分离的HEAD。
只有在该命令(git submodule update --remote (--merge/--rebase))中添加--merge--rebase,才能获得非分离的HEAD,如Simbaanswer所示:默认情况下为master分支。
如果你不那样更新(git submodule update --remote (--merge/--rebase)),那么你需要进入那个子模块,自己在那里做一个分支。
如果你想为上述子模块做贡献(在其中进行新的提交),创建一个新的分支是个好主意。

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,但仍允许递归检出成功。
参见commit 57f22bf(2017年7月28日)和Stefan Beller ( stefanbeller )commit 3ef2538(2017年7月24日)。
(由Junio C Hamano -- gitster --合并至commit 0b75572,2017年12月6日)

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

当子模块位于分支上并且在其超级项目中运行递归 checkout 时,子模块的分支将更新为超级项目 checkout 的内容。
这在当前的Git模型中是非常出乎意料的,例如' submodule update '总是分离子模块HEAD。
尽管有计划在未来不分离子模块HEADS,但当前的行为确实很糟糕,因为它不符合用户预期,并且没有检查提交丢失(只能通过reflog恢复)。
更新HEAD时,无条件地在子模块中分离HEAD。

jvidinwx

jvidinwx2#

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

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在树/提交层存储的关于一个子模块的信息,所以它不知道提交发生在哪个分支上。事实上,存储分支名是行不通的,分支名是可以改变的。另外,如果你在仓库中 checkout 了一个旧的提交,并且需要回滚该子模块,分支应该移回到子模块中吗?这会将新分支位置之后的提交强制转换到未引用的区域中。
分支是供人类使用的,用来理解DAG,以及特定的思路在哪里。Git不在乎我们如何引用提交。它需要一个具体的位置,这样你就可以安全地移动包含的repo,并知道子模块总是会被 checkout 到它当时的位置。唯一的真相是哈希。

1mrurvl1

1mrurvl13#

对于Sourcetree的用户--你会看到同样的行为--克隆会给你一个分离状态的子模块,正如VonC提到的in his answer,如果你想为子模块做贡献,你需要执行一些额外的步骤。
除了从子模块SHA-1创建一个新的分支之外,在大多数情况下,你只需要 checkout 现有分支的头。除非子模块被配置为跟随一个特定的分支,否则这将是master。
您可以打开每个子模块并手动 checkout 其对应的分支,也可以创建一个自定义操作来为您执行此操作(递归!):

    • 要运行的脚本**
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;'"""

这将检查项目中的任何子模块,并 checkout 它们指向的分支(如果没有指定分支,则 checkout master)。这是递归的,因此任何包含子模块的子模块也将被处理。
正如我在an earlier post中所发现的,末尾的额外引号对是必需的。

jv4diomz

jv4diomz4#

.gitmodule中添加**branch选项与子模块的分离行为完全无关**。
git submodule --help中,HEAD分离是git submodule update --remote的默认行为
首先,不需要指定要跟踪的分支origin/master是要跟踪的默认分支。
--很少
使用子模块的远程跟踪分支的状态来更新子模块,而不是使用超级项目记录的SHA-1。使用的远程是分支的远程(branch.<name>.remote),默认为origin。使用的远程分支默认为master
为什么
那么为什么HEAD在update之后被分离呢?因为submodule.$name.update默认行为是checkout
--结帐
checkout 子模块中detached HEAD上的超级项目中记录的提交。这是默认行为,此选项的主要用途是在设置为checkout以外的值时覆盖submodule.$name.update

如何

如果希望子模块自动与远程分支合并,请使用--merge--rebase
--合并
此选项仅对update命令有效。将记录在超级项目中的提交合并到子模块的当前分支中。如果给定此选项,子模块的HEAD将不分离
--重定基
将当前分支重定基到超项目中记录的提交上。如果提供了这个选项,子模块的HEAD将不被分离
你只需要,

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

还有一个选项可以将--merge--rebase设置为git submodule update的默认行为,方法是将submodule.$name.update设置为mergerebase
下面是一个关于如何在.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

xt0899hw

xt0899hw5#

遗憾的是,之前发布的答案没有一个对我有用,因此,我创建了一个简单的脚本:

#/bin/bash
git submodule init
git submodule update
cd <submodule>
git checkout <branch>

这实际上检查出记录在超级项目中的子模块提交,而没有分离的头部。

相关问题