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

Ben*_*tto 1506 git

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

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

在我的工作区域,git log显示我所期待的 - 我在正确的火车上,我不想要的提交,以及那些新的,等等.

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

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

Chr*_*sen 2451

首先,让我们澄清一下HEAD是什么以及当它被分离时它意味着什么.

HEAD是当前签出的提交的符号名称.当HEAD没有分离时("正常" 1情况:你有一个分支检出),HEAD实际指向分支的"ref",分支指向提交.因此HEAD"附着"到分支.进行新提交时,HEAD指向的分支将更新为指向新提交.HEAD会自动跟随,因为它只指向分支.

  • git symbolic-ref HEADyield refs/heads/master
    检出名为"master"的分支.
  • git rev-parse refs/heads/masteryield 17a02998078923f2d62811326d130de991d1a95a
    该提交是主分支的当前提示或"头".
  • git rev-parse HEAD也是产量17a02998078923f2d62811326d130de991d1a95a
    这就是"象征性的参考"意味着什么.它通过其他参考指向一个对象.
    (符号裁判最初实现为符号链接,但后来改为用额外的解释,使他们能够在没有符号连接的平台上使用纯文本文件.)

我们有HEAD→交通refs/heads/master→交通17a02998078923f2d62811326d130de991d1a95a

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

  • git symbolic-ref HEAD 失败了 fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEADyield 17a02998078923f2d62811326d130de991d1a95a
    由于它不是符号引用,它必须直接指向提交本身.

我们有HEAD17a02998078923f2d62811326d130de991d1a95a

使用分离的HEAD要记住的重要一点是,如果它指向的提交是未引用的(没有其他引用可以到达它),那么当你检查其他提交时它将变成"悬空".最终,这些悬空提交将通过垃圾收集过程进行修剪(默认情况下,它们会保留至少2周,并且可以通过HEAD的reflog引用来保持更长时间).

1 这是完全没有做一个分离的头"正常"的工作,你只需要跟踪的你在做什么,以避免鱼类下降的历史了引用日志的.


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

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

git branch temp
git checkout temp
Run Code Online (Sandbox Code Playgroud)

(这两个命令可以缩写为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
Run Code Online (Sandbox Code Playgroud)

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

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

git branch -f master temp
git checkout master
Run Code Online (Sandbox Code Playgroud)

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

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

git branch -d temp
Run Code Online (Sandbox Code Playgroud)

最后,您可能希望推送重新建立的历史记录:

git push origin master
Run Code Online (Sandbox Code Playgroud)

您可能需要添加--force到此命令的末尾以推送远程分支无法"快速转发"到新提交(即您丢弃,或重写某些现有提交,或以其他方式重写了一些历史记录).

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

  • 这是一个很好的答案,但我认为不需要临时分支(虽然我通常使用一个我的自己).`git branch -f master HEAD && git checkout master`就足够了 - 假设你的目标是保持现有的头部但是把它指定为`master`.其他目标也有意义,并呼吁其他食谱. (32认同)
  • 大声笑着关于长度的评论.而我们其他人只是扫描直到我们达到"从你的情况中恢复[...]"的路线,并从那里开始 - 同时做一个心理记录,有一个有用的,很好解释的背景故事,我们可以阅读在一个下雨天._option_阅读更多内容并不会伤害到你,但它可以帮助他人. (32认同)
  • 我同意@AntonioSesto:对于大多数项目(甚至是相当大的项目),你不需要令人难以置信的复杂性,即Git.我的大脑反对努力克服过于明显过度设计的事情.我不需要它,我不想要它. (9认同)
  • 有趣的是`man git-symbolic-ref`:"在过去,`.git/HEAD`是指向`refs/heads/master`的符号链接.当我们想切换到另一个分支时,我们做了` - sf refs/heads/newbranch .git/HEAD`,当我们想知道我们在哪个分支时,我们做了`readlink .git/HEAD`.但是符号链接不是完全可移植的,所以它们现在已被弃用并且具有象征意义默认情况下使用refs(如上所述)." (6认同)
  • 这个答案是帮助我在Eclipse中意外地执行git reset --hard <sha>后让我的origin/master与我的本地同步的最后一步.第一步是执行git reflog并恢复本地提交(请参阅http://stackoverflow.com/questions/5473/undoing-a-git-reset-hard-head1).谢谢. (4认同)
  • 我犯了一个不幸的错误,认为"嘿,我只是在命名我要指向临时的分支时才特别具体的特殊......"我输入了"git branch -f origin/master temp".故事的道德,不要那样做.它最终创建了一个名为"origin/master"的新的本地分支,并创建了许多其他问题.这源于对分支-f如何工作以及本地分支和远程分支之间的差异的误解.本地分支跟踪远程分支. (4认同)
  • 这就是我讨厌git的原因. (4认同)
  • “用独立的头脑做‘正常’的工作是完全可以的,你只需要跟踪你正在做的事情,以避免从引用日志中删除历史记录。”我以为我正在读一本道格拉斯·亚当斯的小说。第二。 (2认同)

Dan*_*iuc 615

这样做:

git checkout master
Run Code Online (Sandbox Code Playgroud)

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

git checkout -b temp
git checkout -B master temp
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的简洁.不是每个人都有时间参与"首先,让我们澄清一下HEAD是什么......"的答案. (300认同)
  • 这是一个危险的回应.到达这个答案的人有不同的状态,"只是做这个来解决它"回答不回答问题.这个很容易破坏工作. (53认同)
  • !"git checkout master"如果分离的头部不是主人的一部分,将导致所有更改丢失! (14认同)
  • @Blauhirn你可能已经检查了提交,而不是分支.分支仍指向相同的提交,但您处于不同的"模式". (3认同)
  • 同意@Archonic 在盲目运行任何命令之前了解 git 的工作原理非常重要。不阅读大答案可以节省时间,但如果你的工作丢失,可能会损失更多时间。 (2认同)

Dmi*_*sky 121

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

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

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

git rebase HEAD master
Run Code Online (Sandbox Code Playgroud)

这个命令:

  1. 退房 master
  2. 标识HEAD返回到HEAD分歧点的父提交master
  3. 播放那些提交 master

最终的结果是,这在所有的提交HEAD而不是master随后也master.master仍然签出.


关于遥控器:

我在rebase中杀死的几个提交被推了出来,而那些在本地提交的新提交不在那里.

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

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

  • git:"首先,重新开始重温你的工作......快速转发大师到HEAD." 我:"太棒了!" (3认同)

man*_*lds 81

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

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

用于可视化它的命令行:

git branch
Run Code Online (Sandbox Code Playgroud)

要么

git branch -a
Run Code Online (Sandbox Code Playgroud)

你会得到如下输出:

* (no branch)
master
branch1
Run Code Online (Sandbox Code Playgroud)

这些* (no branch)节目你是独立的.

你可以通过做一个git checkout somecommit等来到这个状态,它会警告你以下:

你处于"独立的HEAD"状态.您可以环顾四周,进行实验性更改并提交它们,并且您可以放弃在此状态下进行的任何提交,而不会通过执行另一次检出来影响任何分支.

如果要创建新分支以保留您创建的提交,可以再次使用-b和checkout命令(现在或以后).例:

git checkout -b new_branch_name

现在,让他们成为主人:

做一个git reflog甚至只是git log注意你的提交.现在git checkout mastergit merge提交.

git merge HEAD@{1}
Run Code Online (Sandbox Code Playgroud)

编辑:

要添加,git rebase -i不仅要用于删除/删除不需要的提交,还要用于编辑它们.只需在提交列表中提及"编辑",您就可以修改您的提交,然后发出一个git rebase --continue继续.这可以确保你永远不会进入一个独立的HEAD.

  • "@ {1}"有什么作用? (5认同)

Ros*_*one 35

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

简单地跑git checkout -b mynewbranch.

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

  • 是的,它连接到本来应该连接分离头的位置,这正是我想要的。谢谢! (2认同)

amd*_*dev 21

如果你只有主分支并想回到"开发"或功能只是这样做:

git checkout origin/develop
Run Code Online (Sandbox Code Playgroud)

注意:签出原产地/开发.

你处于独立的HEAD状态.您可以环顾四周,进行实验性更改并提交它们,并且您可以放弃在此状态下进行的任何提交,而不会通过执行另一次检出来影响任何分支...

然后

git checkout -b develop
Run Code Online (Sandbox Code Playgroud)

有用 :)

  • 对我有用的不是'git checkout origin/develop',而是'git checkout develop'.使用'origin/develop'总是没有变化,因此留在"HEAD脱离原点/开发".跳过"原点"部分修复了一切. (7认同)

ken*_*orb 17

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

git push origin HEAD:master
Run Code Online (Sandbox Code Playgroud)

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


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

git rebase HEAD master
git checkout master
Run Code Online (Sandbox Code Playgroud)

请参阅:Git:"目前不在任何分支上." 有没有一种简单的方法可以回到分支上,同时保持变化?

  • 这确实将分离的提交发送给origin/master.要将头部连接到本地分支,请执行以下操作:http://stackoverflow.com/a/17667057/776345 (2认同)

小智 10

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

git branch temp
git checkout master
git merge temp
Run Code Online (Sandbox Code Playgroud)

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


use*_*833 10

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

与过去相比,我分析了到达这里所做的事情后,发现自己犯了一个错误。

我的正常流程是:

git checkout master
git fetch
git checkout my-cool-branch
git pull
Run Code Online (Sandbox Code Playgroud)

这次我做了:

git checkout master
git fetch
git checkout origin/my-cool-branch
# You are in 'detached HEAD' state.
Run Code Online (Sandbox Code Playgroud)

问题是我不小心做了:

git checkout origin/my-cool-branch
Run Code Online (Sandbox Code Playgroud)

而不是:

git checkout my-cool-branch
Run Code Online (Sandbox Code Playgroud)

解决方法(在我的情况下)只是运行上面的命令,然后继续执行流程:

git checkout my-cool-branch
git pull
Run Code Online (Sandbox Code Playgroud)


Dan*_*bel 9

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

git push origin HEAD:master
git checkout master        
git pull
Run Code Online (Sandbox Code Playgroud)

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

第二个移动到分支主人.

第三个恢复连接到分支主机的HEAD.

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


geo*_*eon 8

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

git branch -f master HEAD
git checkout master
Run Code Online (Sandbox Code Playgroud)

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

git push -f
Run Code Online (Sandbox Code Playgroud)

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


Ada*_*man 6

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

例如,在分支'dev'中,您可以检出提交asdfasd14314 - >

'git checkout asdfasd14314'
Run Code Online (Sandbox Code Playgroud)

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

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

* (detached from asdfasdf)
  dev
  prod
  stage
Run Code Online (Sandbox Code Playgroud)

但要摆脱独立的头状态并回到开发 - >

'git checkout dev'
Run Code Online (Sandbox Code Playgroud)

然后'git branch'将列出 - >

* dev
  prod
  stage
Run Code Online (Sandbox Code Playgroud)

但是,当然如果你不打算保持对独立头部状态的任何改变,但我发现自己这样做了很多,不打算做任何改变,只是为了查看先前的提交


Var*_*arg 6

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

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

头重新连接!


Gor*_*Ch. 5

而不是做git checkout origin/master

做就是了git checkout master

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


小智 5

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

git checkout -b temp
git add . && git commit -m 'save changes'
git checkout YOUR-BRANCH
git merge temp
git branch -d temp
Run Code Online (Sandbox Code Playgroud)