为什么我的 Git 子模块 HEAD 与 master 分离?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18770545/
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
Why is my Git Submodule HEAD detached from master?
提问by om471987
I am using Git submodules. After pulling changes from server, many times my submodule head gets detached from master branch.
我正在使用 Git 子模块。从服务器拉取更改后,我的子模块头多次与主分支分离。
Why does it happen?
为什么会发生?
I have to always do:
我必须始终这样做:
git branch
git checkout master
How can I make sure that my submodule is always pointing to master branch?
如何确保我的子模块始终指向 master 分支?
回答by mkungla
EDIT:
编辑:
See @SimbaAnswerfor valid solution
submodule.<name>.update
is what you want to change, see the docs- defaultcheckout
submodule.<name>.branch
specify remote branch to be tracked - defaultmaster
submodule.<name>.update
是您要更改的内容,请参阅文档-默认checkout
submodule.<name>.branch
指定要跟踪的远程分支 -默认master
OLD ANSWER:
旧答案:
Personally I hate answers here which direct to external links which may stop working over time and check my answer here(Unless question is duplicate)- directing to question which does cover subject between the lines of other subject, but overall equals: "I'm not answering, read the documentation."
就我个人而言,我讨厌这里指向外部链接的答案,这些链接可能会随着时间的推移停止工作并在此处检查我的答案(除非问题是重复的)- 指向确实涵盖其他主题之间的主题的问题,但总体上等于:“我是不回答,阅读文档。”
So back to the question: Why does it happen?
那么回到问题:为什么会发生?
Situation you described
你描述的情况
After pulling changes from server, many times my submodule head gets detached from master branch.
从服务器拉取更改后,我的子模块头多次与主分支分离。
This is a common case when one does not use submodulestoo often or has just started with submodules. I believe that I am correct in stating, that we allhave been there at some point where our submodule's HEAD gets detached.
这是当一个不使用常见的情况的子模块过于频繁或刚开始与子模块。我相信我的说法是正确的,我们都曾经历过 submodule的 HEAD 分离的某个时刻。
- Cause: Your submodule is not tracking correct branch (default master).
Solution: Make sure your submodule is tracking the correct branch
- 原因:您的子模块没有跟踪正确的分支(默认主模块)。
解决方案:确保您的子模块正在跟踪正确的分支
$ cd <submodule-path>
# if the master branch already exists locally:
# (From git docs - branch)
# -u <upstream>
# --set-upstream-to=<upstream>
# Set up <branchname>'s tracking information so <upstream>
# is considered <branchname>'s upstream branch.
# If no <branchname> is specified, then it defaults to the current branch.
$ git branch -u <origin>/<branch> <branch>
# else:
$ git checkout -b <branch> --track <origin>/<branch>
- Cause: Your parent repo is not configured to track submodules branch.
Solution: Make your submodule track its remote branch by adding new submodules with the following two commands.- First you tell git to track your remote
<branch>
. - you tell git to perform rebase or merge instead of checkout
- you tell git to update your submodule from remote.
- First you tell git to track your remote
- 原因:您的父存储库未配置为跟踪子模块分支。
解决方案:通过使用以下两个命令添加新子模块,使您的子模块跟踪其远程分支。- 首先,您告诉 git 跟踪您的遥控器
<branch>
。 - 你告诉 git 执行 rebase 或 merge 而不是 checkout
- 你告诉 git 从远程更新你的子模块。
- 首先,您告诉 git 跟踪您的遥控器
$ git submodule add -b <branch> <repository> [<submodule-path>]
$ git config -f .gitmodules submodule.<submodule-path>.update rebase
$ git submodule update --remote
- If you haven't added your existing submodule like this you can easily fix that:
- First you want to make sure that your submodule has the branch checked out which you want to be tracked.
- 如果您还没有像这样添加现有的子模块,您可以轻松修复:
- 首先,您要确保您的子模块已检出要跟踪的分支。
$ cd <submodule-path>
$ git checkout <branch>
$ cd <parent-repo-path>
# <submodule-path> is here path releative to parent repo root
# without starting path separator
$ git config -f .gitmodules submodule.<submodule-path>.branch <branch>
$ git config -f .gitmodules submodule.<submodule-path>.update <rebase|merge>
In the common cases, you already have fixed by now your DETACHED HEAD since it was related to one of the configuration issues above.
在常见情况下,您现在已经修复了 DETACHED HEAD,因为它与上述配置问题之一有关。
fixing DETACHED HEAD when .update = checkout
固定 DETACHED HEAD 时 .update = checkout
$ cd <submodule-path> # and make modification to your submodule
$ git add .
$ git commit -m"Your modification" # Let's say you forgot to push it to remote.
$ cd <parent-repo-path>
$ git status # you will get
Your branch is up-to-date with '<origin>/<branch>'.
Changes not staged for commit:
modified: path/to/submodule (new commits)
# As normally you would commit new commit hash to your parent repo
$ git add -A
$ git commit -m"Updated submodule"
$ git push <origin> <branch>.
$ git status
Your branch is up-to-date with '<origin>/<branch>'.
nothing to commit, working directory clean
# If you now update your submodule
$ git submodule update --remote
Submodule path 'path/to/submodule': checked out 'commit-hash'
$ git status # will show again that (submodule has new commits)
$ cd <submodule-path>
$ git status
HEAD detached at <hash>
# as you see you are DETACHED and you are lucky if you found out now
# since at this point you just asked git to update your submodule
# from remote master which is 1 commit behind your local branch
# since you did not push you submodule chage commit to remote.
# Here you can fix it simply by. (in submodules path)
$ git checkout <branch>
$ git push <origin>/<branch>
# which will fix the states for both submodule and parent since
# you told already parent repo which is the submodules commit hash
# to track so you don't see it anymore as untracked.
But if you managed to make some changes locally already for submodule and commited, pushed these to remote then when you executed 'git checkout ', Git notifies you:
但是,如果您已经设法在本地对子模块进行了一些更改并提交,将它们推送到远程,然后当您执行“git checkout”时,Git 会通知您:
$ git checkout <branch>
Warning: you are leaving 1 commit behind, not connected to any of your branches:
If you want to keep it by creating a new branch, this may be a good time to do so with:
The recommended option to create a temporary branch can be good, and then you can just merge these branches etc. However I personally would use just git cherry-pick <hash>
in this case.
创建临时分支的推荐选项可能很好,然后您可以合并这些分支等。但是我个人只会git cherry-pick <hash>
在这种情况下使用。
$ git cherry-pick <hash> # hash which git showed you related to DETACHED HEAD
# if you get 'error: could not apply...' run mergetool and fix conflicts
$ git mergetool
$ git status # since your modifications are staged just remove untracked junk files
$ rm -rf <untracked junk file(s)>
$ git commit # without arguments
# which should open for you commit message from DETACHED HEAD
# just save it or modify the message.
$ git push <origin> <branch>
$ cd <parent-repo-path>
$ git add -A # or just the unstaged submodule
$ git commit -m"Updated <submodule>"
$ git push <origin> <branch>
Although there are some more cases you can get your submodules into DETACHED HEAD state, I hope that you understand now a bit more how to debug your particular case.
尽管还有更多情况可以让您的子模块进入 DETACHED HEAD 状态,但我希望您现在对如何调试您的特定情况有更多了解。
回答by Simba
Adding a branch
optionin .gitmodule
is NOT relatedto the detached behavior of submodules at all. The old answer from @mkungla is incorrect, or obsolete.
添加branch
选项中.gitmodule
的不涉及在所有子模块的分离行为。@mkungla 的旧答案不正确或已过时。
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
? This is caused by the default module update behavior: checkout
.
那么为什么 HEAD 在 之后分离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
.
To explain this weird update behavior, we need to understand how do submodules work?
为了解释这种奇怪的更新行为,我们需要了解子模块是如何工作的?
Quote from Starting with Submodules in book Pro Git
Although sbmodule
DbConnector
is a subdirectory in your working directory, Git sees it as a submodule and doesn't track its contents when you're not in that directory. Instead, Git sees it as a particular commit from that repository.
尽管 sbmodule
DbConnector
是您工作目录中的子目录,但 Git 将其视为子模块,并且当您不在该目录中时不会跟踪其内容。相反,Git 将其视为来自该存储库的特定提交。
The main repo tracks the submodule with its state at a specific point, the commit id. So when you update modules, you're updating the commit id to a new one.
主 repo 跟踪子模块及其在特定点的状态,即提交 id。因此,当您更新模块时,您将提交 ID 更新为新的。
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
Recommended alias:
推荐别名:
git config alias.supdate 'submodule update --remote --merge'
# do submodule update with
git supdate
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
Or configure it in command line,
或者在命令行中配置它,
# replace $name with a real submodule name
git config -f .gitmodules submodule.$name.update merge
References
参考
git submodule --help
- Submodules tutorial from book Pro Git
git submodule --help
- 来自Pro Git一书的子模块教程
回答by j2emanue
i got tired of it always detaching so i just use a shell script to build it out for all my modules. i assume all submodules are on master: here is the script:
我厌倦了它总是分离,所以我只是使用一个 shell 脚本来为我的所有模块构建它。我假设所有子模块都在主模块上:这是脚本:
#!/bin/bash
echo "Good Day Friend, building all submodules while checking out from MASTER branch."
git submodule update
git submodule foreach git checkout master
git submodule foreach git pull origin master
execute it from your parent module
从您的父模块执行它
回答by Johnny Z
Check out my answer here: Git submodules: Specify a branch/tag
在此处查看我的答案: Git 子模块:指定分支/标签
If you want, you can add the "branch = master" line into your .gitmodules file manually. Read the link to see what I mean.
如果需要,您可以手动将“branch = master”行添加到 .gitmodules 文件中。阅读链接以了解我的意思。
EDIT: To track an existing submodule project at a branch, follow VonC's instructions here instead:
编辑:要跟踪分支中现有的子模块项目,请按照 VonC 的说明进行操作:
回答by frontendgirl
The other way to make your submodule to check out the branch is to go the .gitmodules
file in the root folder and add the field branch
in the module configuration as following:
让子模块检出分支的另一种方法是转到.gitmodules
根文件夹中的文件并branch
在模块配置中添加字段,如下所示:
branch = <branch-name-you-want-module-to-checkout>
branch = <branch-name-you-want-module-to-checkout>
回答by deltacrux
As other people have said, the reason this happens is that the parent repo only contains a reference to (the SHA1 of) a specific commit in the submodule – it doesn't know anything about branches. This is how it should work: the branch that was at that commit may have moved forward (or backwards), and if the parent repo had referenced the branch then it could easily break when that happens.
正如其他人所说,发生这种情况的原因是父存储库仅包含对子模块中特定提交(的 SHA1)的引用——它对分支一无所知。它应该是这样工作的:那个提交的分支可能已经向前(或向后)移动,如果父存储库引用了该分支,那么它很容易在发生这种情况时中断。
However, especially if you are actively developing in both the parent repo and the submodule, detached HEAD
state can be confusing and potentially dangerous. If you make commits in the submodule while it's in detached HEAD
state, these become dangling and you can easily lose your work. (Dangling commits can usually be rescued using git reflog
, but it's much better to avoid them in the first place.)
但是,特别是如果您同时在父存储库和子模块中积极开发,detached HEAD
状态可能会令人困惑并具有潜在危险。如果您在子模块处于detached HEAD
状态时在子模块中进行提交,这些将变得悬而未决,您很容易丢失您的工作。(通常可以使用 拯救悬空提交git reflog
,但最好首先避免它们。)
If you're like me, then most of the time if there is a branch in the submodule that points to the commit being checked out, you would rather check out that branch than be in detached HEAD state at the same commit.You can do this by adding the following alias to your gitconfig
file:
如果您像我一样,那么大多数情况下,如果子模块中有一个分支指向要签出的提交,那么您宁愿签出该分支,也不愿在同一提交中处于分离的 HEAD 状态。您可以通过将以下别名添加到您的gitconfig
文件来做到这一点:
[alias]
submodule-checkout-branch = "!f() { git submodule -q foreach 'branch=$(git branch --no-column --format=\"%(refname:short)\" --points-at `git rev-parse HEAD` | grep -v \"HEAD detached\" | head -1); if [[ ! -z $branch && -z `git symbolic-ref --short -q HEAD` ]]; then git checkout -q \"$branch\"; fi'; }; f"
Now, after doing git submodule update
you just need to call git submodule-checkout-branch
, and any submodule that is checked out at a commit which has a branch pointing to it will check out that branch. If you don't often have multiple local branches all pointing to the same commit, then this will usually do what you want; if not, then at least it will ensure that any commits you do make go onto an actual branch instead of being left dangling.
现在,在完成之后,git submodule update
您只需要调用git submodule-checkout-branch
,并且在具有指向它的分支的提交中检出的任何子模块都将检出该分支。如果你不经常有多个本地分支都指向同一个提交,那么这通常会做你想要的;如果没有,那么至少它会确保您所做的任何提交都进入实际分支而不是悬空。
Furthermore, if you have set up git to automatically update submodules on checkout (using git config --global submodule.recurse true
, see this answer), you can make a post-checkout hook that calls this alias automatically:
此外,如果您已将 git 设置为在结帐时自动更新子模块(使用git config --global submodule.recurse true
,请参阅此答案),您可以创建一个自动调用此别名的结帐后挂钩:
$ cat .git/hooks/post-checkout
#!/bin/sh
git submodule-checkout-branch
Then you don't need to call either git submodule update
or git submodule-checkout-branch
, just doing git checkout
will update all submodules to their respective commits and check out the corresponding branches (if they exist).
然后你不需要调用git submodule update
or git submodule-checkout-branch
,只要这样做git checkout
就会将所有子模块更新到它们各自的提交并检查相应的分支(如果它们存在)。