如何将分离的HEAD与主/源调和?

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

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

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

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

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

1176139 次浏览

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

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

命令行来可视化它:

git branch

git branch -a

您将获得如下输出:

* (no branch)masterbranch1

* (no branch)表示您处于分离的头部。

你可以通过git checkout somecommit等来达到这个状态,它会用以下方式警告你:

您处于分离的HEAD状态。您可以环顾四周,进行实验更改并提交它们,您可以丢弃你在这里所做的任何提交不影响任何分支的状态#36825;另一个结帐。

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

git check out-bnew_branch_name

现在,让他们到主:

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

git merge HEAD@{1}

编辑:

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

首先,让我们澄清什么是头以及它被分离时的含义。

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

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

我们有HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

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

  • git symbolic-ref HEAD失败fatal: ref HEAD is not a symbolic ref
  • 0=1
    因为它不是符号ref,所以它必须直接指向提交本身。

我们有HEAD17a02998078923f2d62811326d130de991d1a95a

对于分离的HEAD要记住的重要一点是,如果它指向的提交未被引用(没有其他ref可以到达它),那么当你签出其他提交时,它将变得“悬空”。最终,这种悬空提交将通过垃圾回收机制过程被修剪(默认情况下,它们至少会保留2周,并且可能会通过HEAD的reflg引用而保持更长时间)。

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


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

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

git branch tempgit checkout temp

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

这会将您的HEAD重新连接到新的temp分支。

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

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

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

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

git branch -f master tempgit 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移回原始分支并将其重置回原始提交,这将撤消我们上面所做的一些工作)。

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

简单地运行git checkout -b mynewbranch

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

我遇到了这个问题,当我读到顶部投票的答案时:

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

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

git rebase HEAD master

此命令:

  1. 检查master
  2. HEAD的父提交标识回HEAD偏离master的点
  3. master的顶部播放这些提交

最终的结果是,所有在HEAD中但不在master中的提交也在master中。


关于遥控器:

我在rebase中杀死的几个提交被推了,本地提交的新提交不在那里。

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

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

只要这样做:

git checkout master

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

git checkout -b tempgit checkout -B master temp

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

git ls-remote origin0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        HEAD6f96ad0f97ee832ee16007d865aac9af847c1ef6        refs/heads/HEAD0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        refs/heads/master

我最终解决了这个问题

git push origin :HEAD

如果你只有主分支并想回到“开发”或功能,只需这样做:

git checkout origin/develop

注意:检查起源/发展

你处于分离头状态。你可以环顾四周,进行实验更改并提交它们,您可以丢弃在此中进行的任何提交通过执行另一个签出而不影响任何分支的状态…

然后

git checkout -b develop

它工作:)

您所要做的就是'git check out[分支名称]',其中[分支名称]是您进入分离头部状态的原始分支的名称。(脱离asdfasdf)将消失。

因此,例如,在分支'dev'中,您签出提交asdfasd14314->

'git checkout asdfasd14314'

你现在处于超然状态

'git分支'将列出类似->的内容

* (detached from asdfasdf)devprodstage

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

'git checkout dev'

然后'git分支'将列出->

* devprodstage

但这当然是如果你不打算从分离的头部状态保持任何变化,但我发现自己这样做了很多,不打算做出任何改变,只是为了看看以前的提交

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

git branch tempgit checkout mastergit merge temp

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

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

所以我做了:

git branch -d branchname

然后再次检查分支:

git checkout branchname

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

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

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

git push origin HEAD:master

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


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

git rebase HEAD mastergit checkout master

见:Git:“当前不在任何分支上。”有没有一种简单的方法可以在保持更改的同时回到分支上?

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

git branch -f master HEADgit checkout master

你可能无法推送到起源,因为你的主人已经偏离了起源。如果你确定没有其他人在使用存储库,你可以强制推送:

git push -f

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

git checkout checksum  # You could use this to peek previous checkpointsgit status # You will see HEAD detached at checksumgit checkout master # This moves HEAD to master branch

简而言之,分离的HEAD状态意味着您没有签出到任何分支的HEAD(或Tips)

用一个例子来理解

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

提交1:大师-->branch_HEAD(123 be 6 a 76168 aca 712 a ea 16076 e 971 c 23835 f 8 ca)

提交2:master-->123 be 6 a 76168 aca 712 a ea 16076 e 971 c 23835 f 8 ca-->branch_HEAD(100644 a 76168 aca 712 a ea 16076 e 971 c 23835 f 8 ca)

正如你在上面的提交序列中看到的,你的分支指向你的最新提交。所以在这种情况下,如果你签出提交123 be 6 a 76168 aca 712 a ea 16076 e 971 c 23835 f 8 ca,那么你将处于分离的头部状态,因为你分支的HEAD指向100644 a 76168 aca 712 a ea 16076 e 971 c 23835 f 8 ca,从技术上讲,你在没有分支的HEAD签出。因此,你处于分离的HEAD状态。

理论解释

在这个博客它清楚地说明Git存储库是一个提交树,每个提交都指向它的祖先,每个提交指针都会更新,并且这些指向每个分支的指针存储在. git/refs子目录中。标签存储在. git/refs/tags中,分支存储在. git/refs/head中。如果你查看任何文件,你会发现每个标签对应于一个文件,具有40个字符的提交哈希值,正如上面@Chris Johnsen和@Yaroslav Nikitenko所解释的那样,你可以查看这些参考。

而不是做git checkout origin/master

只是做git checkout master

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

如果你做了一些提交在大师之上,只是想在那里“向后合并”master(即你想让master指向HEAD),单行代码将是:

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

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

正如Chris所指出的,我有以下情况

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

和头部是重新连接!

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

  • 将您的更改提交到一个分支,通常是一个新的分支
  • 然后从遥控器拉出来
  • 然后右键点击项目节点,选择team然后选择show历史
  • 然后右键单击master,选择check out
  • 如果Eclipse告诉您,有两个主机一个本地一个远程,请选择远程

在此之后,您应该能够重新连接到原始主机。

这对我来说是完美的:

1.git stash保存本地修改

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

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

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

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

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

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

如果你需要保留你的改变

  1. 首先,您需要运行git checkout master命令才能将您放回主服务器分支。
  2. 如果您需要保留更改,只需运行git checkout -b changesgit checkout -B master changes

如果你不需要你的改变

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

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

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

以下操作对我有效(仅使用分支主机):

git push origin HEAD:mastergit checkout mastergit pull

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

第二个移动到主分支。

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

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

我今天遇到了这个问题,我更新了一个子模块,但不在任何分支上。我已经提交了,所以藏匿、结帐和取消藏匿都不起作用。我最终选择了分离头部的提交。所以在我提交后(推送失败时),我做了:

git checkout mastergit cherry-pick 99fe23ab

我的想法是:我在一个分离的头脑上,但我想成为主人。假设我的分离状态与主人没有太大的不同,如果我可以将我的承诺应用于主人,我就会被设置。这正是Cherry-Picch所做的。

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

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

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

我的正常流程是:

git checkout mastergit fetchgit checkout my-cool-branchgit pull

这次我做到了:

git checkout mastergit fetchgit 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-branchgit pull

如果您想保存在分离头上所做的更改,只需这样做:创建临时分支并在完成更改后提交它,然后转到Your-BRANCH并将临时分支与之合并。最后,删除临时分支。

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

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

git checkout -b new-branch-name

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

git log

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

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

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

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