克隆和子模块更新后,Git 子模块处于“分离头”状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20794979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Git submodule is in "detached head" state after cloning and submodule update
提问by Barry Fruitman
When I clone my git repo, one of the submodules is in a branch with a strange name, which I think means it has a "detached head" (I'm not even sure what that means).
当我克隆我的 git repo 时,其中一个子模块位于一个名称奇怪的分支中,我认为这意味着它有一个“分离的头”(我什至不确定这是什么意思)。
If I checkout my main branch for the submodule, then run "git submodule update --init --recursive
" it happens again.
如果我检出子模块的主分支,然后运行“ git submodule update --init --recursive
”它会再次发生。
Does anybody know what's going on?
有人知道这是怎么回事吗?
采纳答案by Gary Fixler
The contents of git directories are stored in simple text file manifests (i.e. directory listings) called "trees" that look like the following, where blobs are the contents of files, and trees are yet more trees like this one:
git 目录的内容存储在称为“树”的简单文本文件清单(即目录列表)中,如下所示,其中 blob 是文件的内容,而树是更多的树,如下所示:
100644 blob 0c31be662540ce902cee106f86bfdeef519fc662 .gitignore
100644 blob 1d364edf530c2238e79162bf2d9f30c2af610347 .gitmodules
040000 tree fc6bc39202ec20228e9135cd426110c558b625cd foo
040000 tree 2f9fc460f3a2370ed45b39b2bcaaf9b6e746b823 bar
If bar was a submodule, instead of merely a directory, however, the tree containing it would be listed like this:
如果 bar 是一个子模块,而不仅仅是一个目录,那么包含它的树将像这样列出:
100644 blob 0c31be662540ce902cee106f86bfdeef519fc662 .gitignore
100644 blob 1d364edf530c2238e79162bf2d9f30c2af610347 .gitmodules
040000 tree fc6bc39202ec20228e9135cd426110c558b625cd foo
040000 commit 2f9fc460f3a2370ed45b39b2bcaaf9b6e746b823 bar
Note that instead of bar being a tree, it's now a commit (in a submodule). This is all git stores about a submodule at the tree/commit level, so it can't know what branch a commit was on. In fact, storing branch names can't work. They can change. Also, if you check out an old commit in your repo that needs to roll the submodule back as well, should the branch move back in the submodule? That would cast the commits after that new branch location into unreferenced territory.
请注意, bar 不再是一棵树,它现在是一个提交(在子模块中)。这是关于树/提交级别的子模块的所有 git 存储,因此它无法知道提交位于哪个分支。事实上,存储分支名称是行不通的。他们可以改变。此外,如果您在仓库中检出一个旧提交,该提交也需要回滚子模块,那么分支是否应该移回子模块中?这会将新分支位置之后的提交转换为未引用的区域。
The branches are for humans to use, to make sense of the DAG, and where particular lines of thought are. Git doesn't care how we refer to the commits. It needs a concrete location so you can safely move the containing repo around, and know that the submodule will always be checked out to where it was at that time. The only truth is the hash.
分支供人类使用,以理解 DAG,以及特定思路的位置。Git 不关心我们如何引用提交。它需要一个具体的位置,以便您可以安全地移动包含的 repo,并且知道子模块将始终被检出到当时的位置。唯一的真相是哈希。
回答by VonC
A submodule is alwayschecked out as a detached HEAD (see "Why did git detach my head?"), since the index of the parent repo contains only the SHA1 as a special entryin its index, as explained by Gary Fixler's answer.
子模块始终作为分离的 HEAD 检出(请参阅“为什么 git 分离我的头?”),因为父存储库的索引仅包含 SHA1 作为其索引中的特殊条目,如Gary Fixler的回答所述.
Even if you configure your submodule to follow a branch(or convert an existing submodule to follow a branch), a git submodule update --remote
would checkout the latest SHA1 of that remote branch, but the result would by defaultbe a detached HEAD.
Only by adding --merge
or --rebase
to that command (git submodule update --remote (--merge/--rebase)
) would you get a non-detached HEAD, as seen in Simba's answer): by default, the master
branch.
即使您将子模块配置为跟随分支(或将现有子模块转换为跟随分支),agit submodule update --remote
也会检出该远程分支的最新 SHA1,但默认情况下结果将是分离的 HEAD。
只有在该命令 ( ) 中添加--merge
或--rebase
,git submodule update --remote (--merge/--rebase)
您才能获得非分离的 HEAD,如Simba的回答所示):默认情况下,master
分支。
If you don't update that way (git submodule update --remote (--merge/--rebase)
), then you need to go in that submodule and make a branch yourself there.
如果您不以这种方式更新 ( git submodule update --remote (--merge/--rebase)
),那么您需要进入该子模块并在那里自己创建一个分支。
If you want to contribute to said submodule (making new commits in it), it is a good idea to create a new branch.
如果您想为所述子模块做出贡献(在其中进行新的提交),那么创建一个新分支是个好主意。
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
Note for Git 2.16 (Q1 2018): "git checkout --recursive
" may overwrite and rewind the history of the branch that happens to be checked out in submodule
repositories, which might not be desirable.
Detach the HEAD
but still allow the recursive checkout to succeed in such a case.
Git 2.16(2018 年第一季度)注意事项:“ git checkout --recursive
” 可能会覆盖和回滚恰好在子模块存储库中签出的分支的历史记录,这可能是不可取的。在这种情况下,
分离HEAD
但仍然允许递归结帐成功。
See commit 57f22bf(28 Jul 2017), and commit 3ef2538(24 Jul 2017) by Stefan Beller (stefanbeller
).
(Merged by Junio C Hamano -- gitster
--in commit 0b75572, 06 Dec 2017)
见提交57f22bf(2017年7月28日),以及提交3ef2538(2017年7月24日)由斯蒂芬贝勒(stefanbeller
)。
(由Junio C gitster
Hamano合并-- --在提交 0b75572,2017 年 12 月 6 日)
recursive submodules: detach HEAD from new state
When a submodule is on a branch and in its superproject you run a recursive checkout, the branch of the submodule is updated to what the superproject checks out.
This is very unexpected in the current model of Git as e.g. 'submodule update
' always detaches the submodule HEAD.Despite having plans to have submodule HEADS not detached in the future, the current behavior is really bad as it doesn't match user expectations and it is not checking for loss of commits (only to be recovered via the reflog).
Detach the HEAD unconditionally in the submodule when updating it.
递归子模块:从新状态中分离 HEAD
当子模块位于分支上并且在其超级项目中运行递归检出时,子模块的分支将更新为超级项目检出的内容。
这在当前的 Git 模型中是非常出乎意料的,因为例如 'submodule update
' 总是分离子模块 HEAD。尽管计划在未来不分离子模块 HEADS,但当前的行为确实很糟糕,因为它不符合用户的期望,并且它没有检查提交的丢失(只能通过 reflog 恢复)。
更新时在子模块中无条件地分离 HEAD。
回答by dtmland
For users of Sourcetree- you will observe the same behavior - a clone will give you submodules in a detached state. As VonCmentions in his answerif you want to contribute to the submodule you need to perform some extra steps.
对于Sourcetree 的用户- 您将观察到相同的行为 - 克隆将为您提供处于分离状态的子模块。正如VonC在他的回答中提到的,如果您想为子模块做出贡献,您需要执行一些额外的步骤。
Besides creating a new branch from the point of the submodule SHA-1, in most cases you will simply want to checkout the head of the existing branch. This will be master unless the sub-module is configured to follow a specific branch.
除了从子模块 SHA-1 的角度创建一个新分支之外,在大多数情况下,您只想签出现有分支的头部。除非将子模块配置为遵循特定分支,否则这将是主模块。
You can either open each submodule and manually checkout their corresponding branches, or you can create a custom action to do it for you (recursively!):
您可以打开每个子模块并手动签出其相应的分支,也可以创建一个自定义操作来为您执行此操作(递归!):
Script to Run
要运行的脚本
cmd
Parameters
参数
/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;'"""
This will check for any submodules in your project and checkout the branch that they point to (or master if they don't specify a branch). It is recursive, so any submodules that contain submodules will also be handled.
这将检查您项目中的任何子模块并签出它们指向的分支(如果他们没有指定分支,则为 master)。它是递归的,因此任何包含子模块的子模块也将被处理。
As I found out in an earlier post, the extra pair of quotes on the end are required.
回答by Simba
Adding a branch
optionin .gitmodule
is NOT relatedto the detached behavior of submodules at all.
添加branch
选项中.gitmodule
的不涉及在所有子模块的分离行为。
From git submodule --help
, HEAD detached is the default behaviorof git submodule update --remote
.
从git submodule --help
,头部卸下是默认行为的git submodule update --remote
。
First, there's no need to specify a branch to be tracked. origin/master
is the default branch to be tracked.
首先,无需指定要跟踪的分支。origin/master
是要跟踪的默认分支。
--remote
Instead of using the superproject's recorded SHA-1 to update the submodule, use the status of the submodule's remote-tracking branch. The remote used is branch's remote (
branch.<name>.remote
), defaulting toorigin
. The remote branch used defaults tomaster
.
- 偏僻的
不要使用超级项目记录的 SHA-1 来更新子模块,而是使用子模块的远程跟踪分支的状态。使用的遥控器是分支的遥控器(
branch.<name>.remote
),默认为origin
. 使用的远程分支默认为master
.
Why
为什么
So why is HEAD detached after update
? Because the default behavior of submodule.$name.update
is checkout
.
那么为什么 HEAD 在 之后分离update
?因为的默认行为submodule.$name.update
是checkout
.
--checkout
Checkout the commit recorded in the superproject on a detached HEADin the submodule. This is the default behavior, the main use of this option is to override
submodule.$name.update
when set to a value other thancheckout
.
- 查看
在子模块中的分离 HEAD上检出记录在超级项目中的提交。这是默认行为,此选项的主要用途是
submodule.$name.update
在设置为checkout
.
How
如何
If you want the submodule merged with remote branch automatically, use --merge
or --rebase
.
如果您希望子模块自动与远程分支合并,请使用--merge
或--rebase
。
--merge
This option is only valid for the updatecommand. Merge the commit recorded in the superproject into the current branch of the submodule. If this option is given, the submodule's HEAD will not be detached.
--rebase
Rebase the current branch onto the commit recorded in the superproject. If this option is given, the submodule's HEAD will not be detached.
- 合并
此选项仅对更新命令有效。将超级项目中记录的提交合并到子模块的当前分支中。如果给出这个选项,子模块的 HEAD 将不会被分离。
--rebase
将当前分支变基到超级项目中记录的提交。如果给出这个选项,子模块的 HEAD 将不会被分离。
All you need to do is,
你需要做的就是,
git submodule update --remote --merge
# or
git submodule update --remote --rebase
There's also an option to make --merge
or --rebase
as the default behavior of git submodule update
, by setting submodule.$name.update
to merge
or rebase
.
还有一个选项可以将--merge
或--rebase
作为 的默认行为git submodule update
,方法是设置submodule.$name.update
为merge
或rebase
。
Here's an example about how to config the default update behavior of submodule update in .gitmodule
.
下面是一个关于如何配置子模块更新默认更新行为的例子.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
My whole answer is based on the manual. git submodule --help
.
我的整个答案基于手册。git submodule --help
.