如何将分离的HEAD与master / origin协调?

时间:2011-04-24 17:51:02

标签: git

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

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

在我的工作区域,git log显示了我所期待的 - 我在正确的火车上有我不想要的提交,还有新的提交等等。

但是我只是推送到远程存储库,而且有什么不同 - 我在rebase中杀死的一些提交被推送,而本地提交的新提交不在那里。

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

26 个答案:

答案 0 :(得分:2350)

首先,让我们澄清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要记住的重要一点是,如果它指向的提交是未引用的(没有其他引用可以到达它),那么当你签出其他提交时它将变成“悬空”。最终,这些悬空提交将通过垃圾收集过程进行修剪(默认情况下,它们会被保存至少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

您可能需要在此命令的末尾添加--force以推送远程分支无法“快速转发”到新提交(即您丢弃,或重写某些现有提交,或者否则重写了一些历史)。

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

答案 1 :(得分:576)

这样做:

git checkout master

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

git checkout -b temp
git checkout -B master temp

答案 2 :(得分:115)

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

  

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

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

git rebase HEAD master

此命令:

  1. 结帐master
  2. HEAD的父提交标识回HEADmaster不同的点master
  3. HEAD
  4. 之上播放这些提交

    最终结果是mastermaster中的所有提交都在master中。 git push -f仍然签出。


    关于遥控器:

      

    我在rebase中杀死的一些提交被推了出来,并且在本地提交的新提交不在那里。

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

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

答案 3 :(得分:80)

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

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。

答案 4 :(得分:30)

将您的分离提交添加到自己的分支

只需运行git checkout -b mynewbranch

然后运行git log,您将在此新分支上看到提交现在为HEAD

答案 5 :(得分:21)

如果您只有主分支并希望回到“开发”或功能只是这样做:

git checkout origin/develop

注意:退房 origin / develop

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

然后

git checkout -b develop

它有效:)

答案 6 :(得分:16)

如果您想推送当前已分离的HEAD(请先检查git log),请尝试:

git push origin HEAD:master

将分离的HEAD发送到原始分支。如果您的推送被拒绝,请先尝试git pull origin master从原点获取更改。如果您不关心来自原点的更改并且它被拒绝,因为您做了一些有意的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?

答案 7 :(得分:10)

我今天遇到了这个问题,我很确定通过这样做解决了这个问题:

git branch temp
git checkout master
git merge temp

当我弄清楚如何做到这一点时,我在我的工作电脑上,现在我在个人电脑上遇到了同样的问题。因此,我必须等到周一,当我回到工作计算机上,看看我是怎么做的。

答案 8 :(得分:9)

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

git push origin HEAD:master
git checkout master        
git pull

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

第二个移动到分支主人。

第三个恢复附加到分支主人的HEAD。

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

答案 9 :(得分:7)

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

git branch -f master HEAD
git checkout master

你可能无法推动原点,因为你的主人已经偏离了原点。如果您确定没有其他人使用回购,您可以强行推送:

git push -f

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

答案 10 :(得分:6)

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

git symbolic-ref HEADfatal: ref HEAD is not a symbolic ref

而失败

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

查看提交

之后我做了很多混乱的事情,但似乎修复的只是,

git symbolic-ref HEAD refs/heads/master

头部重新连接!

答案 11 :(得分:5)

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

例如,在分支' dev'你签出提交asdfasd14314 - >

'git checkout asdfasd14314'

你现在处于一个独立的头状态

' git branch'将列出类似 - >

的内容
* (detached from asdfasdf)
  dev
  prod
  stage

但是要离开分离的头状态并回到dev - >

'git checkout dev'

然后' git branch'将列出 - >

* dev
  prod
  stage

但当然,如果你不打算保持对分离头部状态的任何改变,但我发现自己做了很多事情并不打算做任何修改而只是看看之前的提交

答案 12 :(得分:4)

我在搜索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

答案 13 :(得分:4)

今天我遇到了这个问题,我更新了一个子模块,但没有在任何分支上。我已经承诺了,所以藏匿,结账,捣乱都行不通。我结束了挑选超然的头部的承诺。所以我提交后立即(当推送失败时),我做了:

git checkout master
git cherry-pick 99fe23ab

我的想法是:我在一个超然的头上,但我想成为主人。假设我的分离状态与master没什么不同,如果我可以将我的提交应用到master,我会被设置。这正是樱桃选择的目的。

答案 14 :(得分:4)

而不是git checkout origin/master

只做git checkout master

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

答案 15 :(得分:3)

如果你在主人之上做了一些提交,只是想"向后合并" master那里(即你希望master指向HEAD),单行将是:

git checkout -B master HEAD
  1. 这会创建一个名为master的新分支,即使它已经存在(就像移动master那样,也就是我们想要的)。
  2. 新创建的分支设置为指向HEAD,这就是您所在的位置。
  3. 新分支已签出,因此您之后会在master
  4. 我发现这在子存储库的情况下特别有用,它也恰好经常处于分离状态。

答案 16 :(得分:3)

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

如果您需要保留更改

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

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

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

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

答案 17 :(得分:3)

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

所以我做了:

$query = "INSERT INTO `table` (`id`, `name`, `email`) VALUES (' ".$_POST['id']." ', ' ".$_POST['name']." ', ' ".$_POST['email']." ')";

然后再次检查分支:

git branch -d branchname

答案 18 :(得分:1)

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

了解示例

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

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

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

正如您在提交序列的情况下所看到的,您的分支指向您的最新提交。因此,在这种情况下,如果你结帐提交 123be6a76168aca712aea16076e971c23835f8ca 那么你将处于分离头状态,因为你的分支的HEAD指向 100644a76168aca712aea16076e971c23835f8ca 并且从技术上讲,你在HEAD的结账时没有科。因此,您处于分离的HEAD状态。

理论解释

In this Blog显然已经说明了 Git存储库是一个提交树,每个提交指向其祖先,每个提交指针都会更新,这些指向每个分支的指针都存储在.git / refs子目录中。标签存储在.git / refs / tags中,分支存储在.git / refs / heads中。如果您查看任何文件,您会发现每个标记对应一个文件,具有40个字符的提交哈希值,如上所述@Chris Johnsen和@Yaroslav Nikitenko,您可以查看这些引用。

答案 19 :(得分:1)

当我个人发现自己处于这样的情况时,我发现我在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

答案 20 :(得分:0)

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

  • 将您更改为分支,通常是新分支
  • 然后从遥控器拉
  • 然后右键单击项目节点,选择团队,然后选择显示历史记录
  • 然后右键单击主人,选择结帐
  • 如果Eclipse告诉你,有两个主人,一个本地一个遥控器,选择遥控器

在此之后你应该能够重新连接到原始主人。

答案 21 :(得分:0)

这完全适合我:

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'.

答案 22 :(得分:0)

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

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

答案 23 :(得分:0)

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

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

我最终用

修复了
git push origin :HEAD

答案 24 :(得分:-1)

我有同样的问题。我藏着我的变化 git stash并在本地将分支硬重置为先前的提交(我认为这是造成该问题的原因),然后执行了git pull,但现在我没有将这个头卸下。不要忘记git stash apply再次进行更改。

答案 25 :(得分:-2)

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