【问题标题】:How can I reconcile detached HEAD with master/origin?如何协调分离的 HEAD 与 master/origin?
【发布时间】:2011-08-11 22:43:07
【问题描述】:

我是 Git 分支复杂性的新手。我总是在一个分支上工作并提交更改,然后定期推送到我的远程源。

最近,我对一些文件进行了重置以使它们脱离提交暂存状态,后来又进行了rebase -i 以摆脱最近的几个本地提交。现在我处于一种我不太了解的状态。

在我的工作区,git log 完全符合我的预期——我在正确的火车上,我不想消失,还有新的提交,等等。

但我只是推送到远程存储库,有什么不同——我在 rebase 中杀死的几个提交被推送了,而本地提交的新提交不存在。

我认为“master/origin”与 HEAD 分离,但我不是 100% 清楚这意味着什么,如何使用命令行工具将其可视化,以及如何修复它。

【问题讨论】:

  • 你是否在 rebase 之前推送了提交?
  • @manojlds:不确定你的意思。我在 rebase 之前推了一段时间,但不是在之前。
  • 正如您之前是否推送了您在 rebase -i 中删除的提交。从您的回答中我认为不是。
  • @manojlds:正确。我只杀死了比最近推送更新的提交。 (虽然正如我所提到的,我已经推动了,因为我认为一切都很好)
  • 你能解释一下你在I did a reset of some files to get them out of commit staging部分做了什么吗?抱歉这些问题:)

标签: git


【解决方案1】:

查看这里对分离头的基本解释:

http://git-scm.com/docs/git-checkout

命令行可视化:

git branch

git branch -a

你会得到如下输出:

* (no branch)
master
branch1

* (no branch) 表明你处于超然状态。

你可以通过git checkout somecommit 等来达到这种状态,它会警告你以下内容:

您处于“分离 HEAD”状态。你 可以环顾四周,做实验 更改并提交它们,您可以 丢弃您在此所做的任何提交 状态而不影响任何分支 通过执行另一个结帐。

如果你想创建一个新的分支来 保留您创建的提交,您可以这样做 所以(现在或以后)通过使用 -b 和 再次结帐命令。示例:

git checkout -b new_branch_name

现在,让他们进入大师:

做一个git reflog 甚至只是git log 并记下你的提交。现在 git checkout mastergit merge 提交。

git merge HEAD@{1}

编辑:

要添加,使用git rebase -i 不仅可以删除/杀死不需要的提交,还可以编辑它们。只需在提交列表中提及“编辑”,您就可以修改您的提交,然后发出git rebase --continue 继续。这将确保您永远不会进入分离的 HEAD。

【讨论】:

  • 感谢此处提供的详细信息和重要信息。似乎不需要显式合并,但这可视化了一些我将回到的概念。谢谢。
【解决方案2】:

首先,让我们澄清what HEAD is 以及它分离时的含义。

HEAD 是当前签出提交的符号名称。当 HEAD 未分离时(“正常”1 情况:您有一个分支签出),HEAD 实际上指向一个分支的“ref”,而该分支指向提交。 HEAD 因此被“附加”到一个分支上。当您进行新的提交时,HEAD 指向的分支会更新为指向新的提交。 HEAD 自动跟随,因为它只是指向分支。

  • git symbolic-ref HEAD 产生 refs/heads/master
    名为“master”的分支已签出。
  • git rev-parse refs/heads/master产量17a02998078923f2d62811326d130de991d1a95a
    该提交是主分支的当前提示或“头”。
  • git rev-parse HEAD 也产生 17a02998078923f2d62811326d130de991d1a95a
    这就是“符号参考”的含义。它通过其他引用指向一个对象。
    (符号引用最初是作为符号链接实现的,但后来更改为带有额外解释的普通文件,以便它们可以在没有符号链接的平台上使用。)

我们有HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

当 HEAD 被分离时,它直接指向一个提交——而不是通过分支间接指向一个提交。您可以将分离的 HEAD 视为位于未命名的分支上。

  • git symbolic-ref HEADfatal: ref HEAD is not a symbolic ref 失败
  • git rev-parse HEAD 产生 17a02998078923f2d62811326d130de991d1a95a
    由于它不是符号引用,因此它必须直接指向提交本身。

我们有HEAD17a02998078923f2d62811326d130de991d1a95a

使用分离的 HEAD 需要记住的重要一点是,如果它指向的提交是未引用的(没有其他 ref 可以到达它),那么当您签出其他提交时,它将变得“悬空”。最终,此类悬空提交将通过垃圾收集过程进行修剪(默认情况下,它们至少保留 2 周,并且可能会通过 HEAD 的 reflog 引用而保留更长时间)。

1 使用分离的 HEAD 进行“正常”工作是完全可以的,您只需要跟踪您正在做的事情以避免不得不从 reflog 中删除丢弃的历史记录。


交互式 rebase 的中间步骤是使用分离的 HEAD 完成的(部分是为了避免污染活动分支的 reflog)。如果您完成了完整的 rebase 操作,它将使用 rebase 操作的累积结果更新您的原始分支,并将 HEAD 重新附加到原始分支。我的猜测是您从未完全完成变基过程;这将为您留下一个分离的 HEAD,指向最近由 rebase 操作处理的提交。

要从您的情况中恢复,您应该创建一个分支,该分支指向您分离的 HEAD 当前指向的提交:

git branch temp
git checkout temp

(这两个命令可以简写为git checkout -b temp

这会将您的 HEAD 重新附加到新的 temp 分支。

接下来,您应该将当前提交(及其历史记录)与您期望工作的正常分支进行比较:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(您可能想要尝试使用日志选项:添加-p,离开--pretty=… 以查看整个日志消息等)

如果您的新 temp 分支看起来不错,您可能需要更新(例如)master 以指向它:

git branch -f master temp
git checkout master

(这两个命令可以简写为git checkout -B master temp

然后您可以删除临时分支:

git branch -d temp

最后,你可能想要推送重建的历史:

git push origin master

如果远程分支不能“快进”到新的提交(即你删除了,或者重写了一些现有的提交,或者以其他方式重写了一些一点历史)。

如果您正在进行 rebase 操作,您可能应该清理它。您可以通过查找目录.git/rebase-merge/ 来检查是否正在进行变基。您可以通过删除该目录来手动清理正在进行的变基(例如,如果您不再记得活动变基操作的目的和上下文)。通常你会使用git rebase --abort,但这会做一些你可能想要避免的额外重置(它将 HEAD 移回原始分支并将其重置回原始提交,这将撤消我们在上面所做的一些工作)。

【讨论】:

  • 来自man git-symbolic-ref 的有趣:“过去,.git/HEAD 是指向refs/heads/master 的符号链接。当我们想切换到另一个分支时,我们做了ln -sf refs/heads/newbranch .git/HEAD,当我们想知道我们在哪个分支,我们做了readlink .git/HEAD。但是符号链接并不是完全可移植的,所以它们现在已被弃用,并且默认使用符号引用(如上所述)。”
  • 这个答案是帮助我在 Eclipse 中意外执行 git reset --hard 后让我的 origin/master 与本地同步的最后一步。第一步是执行 git reflog 并恢复本地提交(请参阅stackoverflow.com/questions/5473/undoing-a-git-reset-hard-head1)。谢谢。
  • 我同意@AntonioSesto:对于大多数项目(即使是相当大的项目),您不需要 Git 令人难以置信的复杂性。我的大脑在与明显过度设计的东西作斗争时反抗。我不需要它,我也不想要它。
  • 这是一个很好的答案,但我认为不需要临时分支(尽管我通常自己使用一个)。 git branch -f master HEAD && git checkout master 就足够了——假设您的目标是保留当前的头脑,但将其指定为 master。其他目标也很有意义,需要其他方法。
  • 在关于长度的评论中大声笑。而我们其他人只是简单地浏览,直到我们到达“从你的情况中恢复 [...]”的那一行,然后从那里开始——同时在心里记下有一个有用的、解释清楚的背景故事,我们可以阅读在下雨天。 选择阅读更多内容不会伤害您,但它确实可以使他人受益。
【解决方案3】:

将分离的提交放到它自己的分支上

只需运行git checkout -b mynewbranch

然后运行git log,你会看到这个新分支上的提交现在是HEAD

【讨论】:

  • 如果我这样做,mynewbranch 会附加任何东西吗?
  • 是的,它连接到分离头部的位置,这正是我想要的。谢谢!
【解决方案4】:

我遇到了这个问题,当我读到票数最高的答案时:

HEAD 是当前签出提交的符号名称。

我想:啊哈!如果HEAD 是当前结帐提交的符号名称,我可以通过将其与master 重新定位来将其与master 协调一致:

git rebase HEAD master

这个命令:

  1. 签出master
  2. 标识HEAD的父提交回到HEADmaster不同的点
  3. master 之上播放这些提交

最终结果是所有在HEAD 中但不在master 中的提交也都在master 中。 master 仍处于签出状态。


关于遥控器:

我在变基中杀死的几个提交被推送,而本地提交的新提交不存在。

无法再使用本地历史记录快速转发远程历史记录。您需要强制推送 (git push -f) 以覆盖远程历史记录。如果您有任何合作者,与他们协调通常是有意义的,这样每个人都在同一个页面上。

master 推送到远程origin 后,您的远程跟踪分支origin/master 将更新为指向与master 相同的提交。

【讨论】:

  • git:“首先,倒带 head 以在其上重播您的工作......将 master 快进到 HEAD。”我:“很好!”
  • 这个建议创造了各种平行宇宙 FML
  • 哎呀。很抱歉听到这个消息。考虑找到您想要将分支重置为使用git reflog 的提交,然后使用git rest —hard $commit 将您的分支重置为该提交
  • 这非常好,完全符合我的工作流程所需,但实际上与我认为在第 3 点下描述的有点不同:它在分歧点和 master 之间播放提交在分离的HEAD之上。换句话说,在分离的HEAD 上天真地完成的提交正是我想要的,即历史上的某个地方,而不是在master 之上。我通常会为此使用交互式变基。旁注:git rebase master HEAD 做相反的事情,并在master 之上的分离的HEAD 上播放提交,如this answer中所述。
【解决方案5】:

这样做:

git checkout master

或者,如果您有想要保留的更改,请执行以下操作:

git checkout -b temp
git checkout -B master temp

【讨论】:

  • 这是一个危险的反应。得到这个答案的人有不同的状态,“只是这样做来解决它”的回答不回答问题。这很容易破坏工作。
  • !"git checkout master" 如果分离的头部不是 master 的一部分,将导致所有更改丢失!!
  • @Blauhirn 您可能签出了提交,而不是分支。分支仍然指向同一个提交,但你处于不同的“模式”。
  • git reset 应该带有警告“如果您不知道自己在做什么,请停止它”。刚刚从一个小时的恐惧中恢复过来,以为我失去了最后一周的工作。谢谢!
  • 同意@Archonic 在盲目运行任何命令之前了解 git 的工作原理很重要。您可以通过不阅读重要答案来节省时间,但如果您的工作丢失,可能会浪费更多时间。
【解决方案6】:

我进入了一个非常愚蠢的状态,我怀疑其他人会发现这很有用....但以防万一

git ls-remote origin
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        HEAD
6f96ad0f97ee832ee16007d865aac9af847c1ef6        refs/heads/HEAD
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        refs/heads/master

我最终解决了这个问题

git push origin :HEAD

【讨论】:

    【解决方案7】:

    如果您只有 master 分支并想返回“开发”或功能,请执行以下操作:

    git checkout origin/develop
    

    注意:检查 origin/develop

    您处于分离 HEAD 状态。你可以环顾四周,做实验 更改并提交它们,您可以丢弃您在此所做的任何提交 在不影响任何分支的情况下执行另一次结帐...

    然后

    git checkout -b develop
    

    它有效:)

    【讨论】:

    • 对我有用的不是“git checkout origin/develop”,而是“git checkout develop”。使用 'origin/develop' 始终不会导致任何变化,从而保持在“HEAD detached at origin/develop”。跳过“原点”部分可以解决所有问题。
    【解决方案8】:

    您所要做的就是“git checkout [branch-name]”,其中 [branch-name] 是您进入分离头部状态的原始分支的名称。 (与 asdfasdf 分离)将消失。

    例如,在分支“dev”中,您检查提交 asdfasd14314 ->

    'git checkout asdfasd14314'
    

    你现在处于分离的头部状态

    'git branch' 会列出类似 ->

    * (detached from asdfasdf)
      dev
      prod
      stage
    

    但要摆脱分离的头部状态并返回开发->

    'git checkout dev'
    

    然后'git branch'将列出->

    * dev
      prod
      stage
    

    但那当然是如果您不打算保留分离头状态的任何更改,但我发现自己这样做很多不是为了进行任何更改,而只是为了查看以前的提交

    【讨论】:

      【解决方案9】:

      我今天刚遇到这个问题,我很确定我通过以下方式解决了它:

      git branch temp
      git checkout master
      git merge temp
      

      当我想出如何做到这一点时,我在我的工作计算机上,现在我在我的个人计算机上遇到了同样的问题。所以必须等到星期一我回到工作电脑前才能看到我是怎么做到的。

      【讨论】:

      • @StarShine Kenorb 修复了它。现在它将您分离的提交保存到一个新的分支 temp,切换到 master,并将 temp 合并到 master。
      • 我不知道为什么人们不赞成这个,它解决了我的问题统计,但你可能想要包括删除临时分支命令。
      【解决方案10】:

      对我来说,这就像再次删除本地分支一样简单,因为我没有任何想要推送的本地提交:

      所以我做到了:

      git branch -d branchname
      

      然后再次检查分支:

      git checkout branchname
      

      【讨论】:

        【解决方案11】:

        在我的例子中,我运行了git status,我看到我的工作目录中有一些未跟踪的文件。

        为了使变基工作,我只需要清理它们(因为我不需要它们)。

        【讨论】:

          【解决方案12】:

          如果你想推送你当前分离的 HEAD(之前检查git log),试试:

          git push origin HEAD:master
          

          将分离的 HEAD 发送到原点的主分支。如果您的推送被拒绝,请先尝试git pull origin master 以获取来自源的更改。如果您不关心来自 origin 的更改并且它被拒绝,因为您做了一些故意的 rebase 并且您想用当前分离的分支替换 origin/master - 那么您可以强制它(-f)。如果您失去了对以前提交的某些访问权限,您可以随时运行 git reflog 来查看所有分支的历史记录。


          要返回主分支,同时保留更改,请尝试以下命令:

          git rebase HEAD master
          git checkout master
          

          见:Git: "Not currently on any branch." Is there an easy way to get back on a branch, while keeping the changes?

          【讨论】:

          • 这确实将分离的提交发送到 origin/master。要将头部附加到本地分支,请执行以下操作:stackoverflow.com/a/17667057/776345
          • 当我这样做时,我得到 This repository is configured for Git LFS but 'git-lfs' is not found on your path.如果您不再希望使用 Git LFS,请通过删除 .git/hooks/post-checkout 来移除此挂钩。
          【解决方案13】:

          如果你完全确定 HEAD 状态良好:

          git branch -f master HEAD
          git checkout master
          

          您可能无法推送到原点,因为您的主人已经偏离原点。如果您确定没有其他人在使用该 repo,您​​可以强制推送:

          git push -f
          

          如果您在没有其他人使用的功能分支上,则最有用。

          【讨论】:

            【解决方案14】:
            git checkout checksum  # You could use this to peek previous checkpoints
            git status # You will see HEAD detached at checksum
            git checkout master # This moves HEAD to master branch
            

            【讨论】:

              【解决方案15】:

              简单来说,分离的 HEAD 状态意味着您没有签出到任何分支的 HEAD(或提示)

              用例子理解

              在大多数情况下,一个分支是多个提交的序列,例如:

              提交 1: master-->branch_HEAD(123be6a76168aca712aea16076e971c23835f8ca)

              提交 2: master-->123be6a76168aca712aea16076e971c23835f8ca-->branch_HEAD(100644a76168aca712aea16076e971c23835f8ca)

              正如您在上面的提交序列中看到的那样,您的分支指向您的最新提交。因此,在这种情况下,如果您签出提交 123be6a76168aca712aea16076e971c23835f8ca 那么您将处于分离的头部状态,因为您的分支的 HEAD 指向 100644a76168aca712aea16076e971c23835f8ca 并且从技术上讲,您在 HEAD 处签出 no分支。因此,您处于分离的 HEAD 状态。

              理论解释

              In this Blog 明确说明 Git 存储库是一个提交树,每个提交指向其祖先,每个提交指针都会更新,这些指向每个分支的指针存储在 .git/refs 子目录中。标签存储在 .git/refs/tags 中,分支存储在 .git/refs/heads 中。如果您查看任何文件,您会发现每个标签对应于一个文件,具有 40 个字符的提交哈希,正如上面@Chris Johnsen 和 @Yaroslav Nikitenko 所解释的,您可以查看这些参考资料。

              【讨论】:

                【解决方案16】:

                而不是git checkout origin/master

                只要git checkout master

                然后git branch 将确认您的分支。

                【讨论】:

                  【解决方案17】:

                  如果您在 master 之上进行了一些提交,并且只想在那里“向后合并”master(即,您希望 master 指向 HEAD),单线应该是:

                  git checkout -B master HEAD
                  
                  1. 这会创建一个名为master 的新分支,即使它已经存在(这就像移动master,这就是我们想要的)。
                  2. 新创建的分支设置为指向HEAD,这就是你所在的位置。
                  3. 新分支已签出,之后您将使用master

                  我发现这在子存储库的情况下特别有用,子存储库也经常处于分离状态。

                  【讨论】:

                    【解决方案18】:

                    正如克里斯所指出的,我有以下情况

                    git symbolic-ref HEAD 失败并显示 fatal: ref HEAD is not a symbolic ref

                    但是 git rev-parse refs/heads/master 指向一个可以恢复的良好提交(在我的情况下是最后一次提交,您可以使用 git show [SHA] 看到该提交

                    在那之后我做了很多乱七八糟的事情,但似乎已经解决的只是,

                    git symbolic-ref HEAD refs/heads/master

                    头部重新连接!

                    【讨论】:

                    • 谢谢!我的头已经脱离了。我可以赶上它,但他们只是碰巧指向同一个提交,而不是指向指向提交的 master。好提示=D
                    【解决方案19】:

                    如果您在 Eclipse 中使用 EGit: 假设你的主人是你的主要开发分支

                    • 提交你的更改到一个分支,通常是一个新的
                    • 然后从遥控器拉出
                    • 然后右键单击项目节点,选择团队,然后选择显示历史记录
                    • 然后右击master,选择check out
                    • 如果Eclipse告诉你,有两个master一个本地一个远程,选择远程

                    在此之后,您应该能够重新连接到 origin-master。

                    【讨论】:

                      【解决方案20】:

                      这对我来说非常有效:

                      1.git stash 保存本地修改

                      如果您想放弃更改
                      git clean -df
                      git checkout -- .
                      git clean 删除所有未跟踪的文件(警告:虽然它不会删除 .gitignore 中直接提到的被忽略的文件,但它可能会删除位于文件夹中的被忽略的文件)并且 git checkout 会清除所有未暂存的更改。

                      2.git checkout master切换到主分支(假设你要使用master)
                      3.git pull 从主分支拉最后一次提交
                      4.git status 以检查一切看起来都很棒

                      On branch master
                      Your branch is up-to-date with 'origin/master'.
                      

                      【讨论】:

                        【解决方案21】:

                        当我个人发现自己处于一种情况时,当我不在master 中时做了一些更改(即HEADmaster 的正上方分离,并且两者之间没有提交)可能有帮助:

                        git stash # HEAD has same content as master, but we are still not in master
                        git checkout master  # switch to master, okay because no changes and master
                        git stash apply  # apply changes we had between HEAD and master in the first place
                        

                        【讨论】:

                          【解决方案22】:

                          我遇到了同样的问题,我已经通过以下步骤解决了。

                          如果您需要保留更改

                          1. 首先你需要运行git checkout master命令让你回到master 分支。
                          2. 如果您需要保留更改,只需运行 git checkout -b changesgit checkout -B master changes

                          如果您不需要更改

                          1. 要从分支中删除所有未跟踪的文件,请运行 git clean -df

                          2. 然后您需要清除存储库中所有未暂存的更改。为此,您必须运行 git checkout --

                          3. 最后你必须使用git checkout master 命令将你的分支放回主分支。

                          【讨论】:

                            【解决方案23】:

                            以下对我有用(仅使用分支主):

                            git push origin HEAD:master
                            git checkout master        
                            git pull
                            

                            第一个将分离的 HEAD 推送到远程源。

                            第二个移动到分支master。

                            第三个恢复连接到分支 master 的 HEAD。

                            如果推送被拒绝,第一个命令可能会出现问题。但这将不再是分离头的问题,而是分离头不知道一些远程变化的事实。

                            【讨论】:

                            • 没用,我得到了:这个存储库是为 Git LFS 配置的,但是在你的路径上找不到“git-lfs”。如果您不再希望使用 Git LFS,请通过删除 .git/hooks/pre-push 来移除此挂钩。并且您目前不在分支机构。请指定要合并的分支。
                            【解决方案24】:

                            我今天遇到了这个问题,我更新了一个子模块,但不在任何分支上。我已经提交了,所以 stashing、checkout、unstashing 是行不通的。我最终选择了分离头的提交。所以在我提交之后(当推送失败时),我做了:

                            git checkout master
                            git cherry-pick 99fe23ab
                            

                            我的想法是:我在一个超然的头上,但我想成为主人。假设我的分离状态与主人没有太大不同,如果我可以将我的提交应用于主人,我会被设置。这正是cherry-pick 所做的。

                            【讨论】:

                              【解决方案25】:

                              我遇到了同样的问题。我把我的改变藏起来 git stash 并将本地分支硬重置为先前的提交(我认为是它导致的)然后做了一个git pull,我现在没有让那个头分离。不要忘记git stash apply 再次进行更改。

                              【讨论】:

                                【解决方案26】:

                                我在搜索You are in 'detached HEAD' state.时发现了这个问题

                                在分析了我为到达这里所做的一切之后,与我过去所做的相比,我发现我犯了一个错误。

                                我的正常流程是:

                                git checkout master
                                git fetch
                                git checkout my-cool-branch
                                git pull
                                

                                这次我做到了:

                                git checkout master
                                git fetch
                                git checkout origin/my-cool-branch
                                # You are in 'detached HEAD' state.
                                

                                问题是我不小心做了:

                                git checkout origin/my-cool-branch
                                

                                而不是:

                                git checkout my-cool-branch
                                

                                修复(在我的情况下)只是运行上述命令,然后继续流程:

                                git checkout my-cool-branch
                                git pull
                                

                                【讨论】:

                                • 完美解决方案。
                                • @user664833 感谢您的完美回答。事实上,类似的事情也发生在我身上。
                                【解决方案27】:

                                如果您想保存在分离头上所做的更改,只需执行以下操作:创建临时分支并在完成更改后提交它,然后转到 YOUR-BRANCH 并将临时分支与其合并。最后,删除临时分支。

                                git checkout -b temp
                                git add . && git commit -m 'save changes'
                                git checkout YOUR-BRANCH
                                git merge temp
                                git branch -d temp
                                

                                【讨论】:

                                  【解决方案28】:

                                  最简单的解决方案是创建一个新分支,

                                  git checkout -b new-branch-name
                                  

                                  然后通过命令检查你的提交日志,

                                  git log
                                  

                                  如果一切都匹配,则通过 :q 退出

                                  现在通过命令将所有更改推送到新分支

                                  git push --set-upstream origin new-branch-name
                                  

                                  现在,问题已解决,您的本地 git HEAD 已附加到新分支,您可以从门户提出拉取请求。

                                  【讨论】:

                                    猜你喜欢
                                    • 2011-05-20
                                    • 1970-01-01
                                    • 2012-01-02
                                    • 2012-05-22
                                    • 2022-07-02
                                    • 2020-07-12
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多