【问题标题】:git push, now I have a detached headgit push,现在我有一个分离的头
【发布时间】:2019-02-06 23:08:05
【问题描述】:

我正在一个本地分支 foo 工作,该分支拥有丰富而有用的历史。我做了一堆更改并提交它们。 git status 说:

On branch foo Your branch is ahead of 'origin/foo' by 1 commit. (use "git push" to publish your local commits)

所以我继续输入git push

这似乎工作得很好。快速git status 透露:

On branch foo Your branch is up to date with 'origin/foo'. nothing to commit, working tree clean

我切换到我的本地主主分支(称为 feature1git checkout feature1。没问题。然后我 git pull 添加我所有同事的更改。

现在我想切换回 foo 以合并我刚刚拉入 foofeature1 更改。

编辑(我在打字和发帖时都错过了这个!这是关键!!!)

git checkout origin\foo

你瞧!我收到了这条我从未见过的消息:

Note: checking out 'origin/foo'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at f5a29b1083 cosmetic changes for code review

现在git status 的结果是

编辑(更正):

HEAD detached at origin/foo
nothing to commit, working tree clean

所以我的问题是多方面的:

1) 我做错了什么?这是我长期以来一直在做的事情,但以前从未发生过这样的事情。

2) 如何确保不再发生这种情况?

3) 当我将来将 foo 合并到 feature1 时,如何在不丢失我的工作和(更重要的是)不污染每个人的历史的情况下解决这个问题?

【问题讨论】:

  • 消息 "checking out 'origin/foo'" 如果本地分支 foo 不存在但有一个(并且只有一个)远程跟踪分支foo(在这种情况下为origin/foo)。但在这种情况下,它也应该创建本地分支foo。如果您签出除分支以外的任何内容(提交哈希、标签、HEAD~1 等相对引用),您最终可能会处于“分离的 HEAD”状态。但是,我不知道为什么您当地的分支机构突然消失了。您的回购可能会以某种方式损坏。运行git fsck 找出答案。
  • 执行git for-each-ref '**/foo' 并包含结果?
  • git checkout feature1 之后运行git pull 有没有发生什么异常?
  • @axiac git fsck 揭示了一些悬空的 blob、提交和树。太多了,甚至无法显示。

标签: git


【解决方案1】:

每次编辑:啊,你基本上跑了git checkout origin/foo。 (反斜杠拼写是特定于 Windows 的,但它的正斜杠变体适用于任何地方。)

git checkout 命令首先尝试将任何名称作为 branch 名称,即 refs/heads/<em>whatever</em>。如果这有效——如果它是一个有效的分支名称——Git 检查该分支的提示提交并将HEAD 附加到该分支,这样你就可以“在分支上”,因为git status 将放吧。

但如果一个全名为refs/heads/<em>whatever</em> 的分支确实存在,Git 最终会尝试根据the gitrevisions documentation 中概述的六步过程来解析该名称。在您的情况下,此过程最终会找到 refs/remotes/origin/foo。这 不是 一个分支名称,但 一个有效的提交哈希,所以 Git 将该特定提交检出为“分离的 HEAD”。 Git 不会在 HEAD 中存储分支名称,而是存储提交的原始哈希 ID。

最终,所有这一切都依赖于 Git 中 HEAD 的双重性质:它既是 当前分支 当前提交 .为此,Git 通常会在HEAD 中写入一个分支名称,并使用分支名称本身来记录提交哈希。这就是“附加 HEAD”案例。为了支持离开分支,Git 愿意将原始提交哈希 ID 写入 HEAD

你可以问 Git:HEAD 叫什么分支? 使用 git symbolic-ref HEAD。这会从 HEAD 中获取名称,而无需获取提交 ID。如果您处于 detached-HEAD 模式,它会给您一个错误。

或者,您可以问 Git:HEAD 名称是什么提交哈希 ID? 使用 git rev-parse HEAD。这会从HEAD 获取提交哈希 ID,如果您处于附加 HEAD 模式,则使用分支名称,如果您处于分离 HEAD 模式,则使用原始哈希 ID。无论哪种方式都有效。 (它在HEAD 包含分支名称但分支不存在的罕见但并非不可能的情况下失败。这种情况在新的完全空的存储库中是正常的,并且可以通过git checkout --orphan 在任何其他时间。)

(注意:有一个中间步骤,git checkout 尝试创建一个分支名称。这有时被称为“DWIM 选项”或“按我的意思做”。它通过查看来工作您所有的远程跟踪名称,看看是否有一个与您提供的名称完全匹配,除了其中的origin/。)


为此,您的.git 目录中必须有一个名为foo 的文件。此文件必须包含以下文本:

ref: refs/remotes/origin/foo

或成为refs/remotes/origin/foo 的符号链接。要查看哪个,请尝试:

ls -l .git/foo

和:

cat .git/foo

此外,not 必须有一个名为 foo分支,因为 Git 会更喜欢分支而不是文件/符号链接:

$ git checkout diff-merge-base
Switched to branch 'diff-merge-base'
$ ln -s refs/remotes/origin/master .git/master
$ git checkout master
warning: refname 'master' is ambiguous.
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

但是:

$ rm .git/master
$ echo 'ref: refs/remotes/origin/master' > .git/foo
$ git checkout foo
Note: checking out 'foo'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
... [snip]
$ git status
HEAD detached at origin/master
nothing to commit, working tree clean

(删除.git/foo 并使用git checkout master 可以正常工作。)

这一切是如何在您的.git 目录中发生的是个谜。

【讨论】:

  • 感谢您的快速回复!但是我在粘贴时犯了一个错误。请再看看我的问题并查看编辑(我应该在粘贴“story/RUN-16657_C_log_after_build”时粘贴“foo”——我试图简化实际的分支名称)。
  • 答案的核心仍然是:必须有一个.git/foo,它是一个将Git 指向refs/remotes/origin/... 的常规文件或符号链接。
  • 我在发帖时发现了另一个错误。查看带有评论的编辑:“这是关键!”。我想你会立即发现我的错误。
  • 是的,在答案中添加了前面部分,将剩余部分(不适用,因为这不是实际问题)移动到第二部分。
  • 我特别喜欢你对 Git 中两个“头”的解释。这种双重含义常常使我感到困惑。谢谢!
【解决方案2】:
  1. 签发时间
    git checkout origin/foo

这与本地 foo 分支冲突。

  1. 您可以只 git checkout foo; git pull 或删除当前的 foo 分支,然后再次检查;

  2. 你不会失去工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-14
    • 2013-10-31
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    • 2013-08-15
    • 2016-12-22
    相关资源
    最近更新 更多