git:'git reset --hard bd53134后的独立头

时间:2013-11-12 08:09:38

标签: git reset

我在分支机构工作,需要撤消一些提交。所以我做了

$> git reset --hard bd53134

这具有预期的效果,除了我现在有一个独立的头:(

$> git status
HEAD detached at bd53134

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:10)

看起来你可能仍在四处寻找,所以这里有一些背景知识。您在评论中提到您开始git rebase并且始终抱怨git rebase --continue抱怨。 (这确实应该是原始问题的一部分。)

首先注意:HEAD可以正常(“未分离”?)或“分离”。 “普通”HEAD只包含分支名称。如果您“在分支机构master上”,HEAD只是说“在分支主机上”。一个“分离的HEAD”,听起来像法国大革命中的东西,而不是原始的SHA-1提交ID。我喜欢在下面的图中将附加的HEAD编写为HEAD=branch,然后使用箭头指向一个特定的提交来显示分支指向的位置。

在开始使用rebase之前,您有一个可能如下所示的提交图:

...- A - B - E - F         <-- master, origin/master
           \
             C - D         <-- HEAD=branch

在这种情况下,我假设你从git checkout -b branch做了master,并在branch上做了一些提交(创建C和{{1} }),然后可能会执行一个Dgit checkout master来自“远程git pull”的提交EF。然后,您使用origin返回branch(因此git checkout branch)。

然后,您决定应在HEAD=branch之上重新定位CD,从而提供更多线性提交序列:

F

(我稍后会展示为什么...- A - B - E - F <-- master, origin/master \ C' - D' <-- HEAD=branch C'代替D'C。)所以你运行D到“移动“将git rebase masterC提交到D的提示。

Rebase实际上并没有移动提交。它的作用是复制一些现有的提交,使新的“做同样的事情”并且“同样好”(我们希望!)。因此,rebase保持masterC。它使用一个特殊标签D来跟踪提交ORIG_HEAD(和一堆额外的D文件,以跟踪整个rebase操作中的所有进度 - 这些文件实际上是git知道rebase正在“进行中”。)

Rebase通过添加此.git/rebase-apply/和“分离HEAD”来启动该过程。它将“分离的HEAD”设置为将直接指向到rebase的目标(在这种情况下为commit ORIG_HEAD)。 (通过探讨,似乎文档略微关于它重置分支。但是在旧版本的git中可能会有所不同;我认为文档在某一点上是准确的。)因此:

F

然后,对于每次提交(此处为...- A - B - E - F <-- master, origin/master \ \ \ \...... HEAD [detached] \ C - D <-- ORIG_HEAD, branch C),它会获取提交中所做的更改,并尝试将相同的更改应用于D提交。如果一切顺利 - 它通常会 - 它使用与旧提交相同的消息进行新提交。那是提交HEAD

C'

成功将...- A - B - E - F <-- master, origin/master \ \ \ C'..... HEAD [detached] \ C - D <-- ORIG_HEAD, branch 应用于C以使F关闭C'后,rebase命令会继续尝试将F应用于新版本({1}}但仍然分离了DHEAD。但是,这次出现问题:补丁不适用:

C'

此时,您的提交图看起来就像我上面绘制的(有些混乱)图。

作为rebase打印,您可以:

  • 手动和CONFLICT ... Failed to merge in the changes. Patch failed at ... The copy of the patch that failed is found in: ... When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort".
  • 解决问题
  • 选择使用git rebase --continue
  • 删除提交(在本例中为D
  • 使用git rebase --skip退出整个内容。

选择最后一个选项告诉rebase停止rebase尝试,将git rebase --abort恢复原状,并删除“rebase in progress”状态/跟踪文件。这也会丢弃整个新的链(但尚未标记为分支)提交。 (从技术上讲,他们仍然在那里,在reflog中。你通常不会看到它们。)

执行第一个(“手动解析”)或选择中间(“跳过”)选项,让rebase继续向前。假设您解决了问题并HEAD。一旦rebase用完了提交 - 而git rebase --continue是最后一个 - 它将分支名称移动到最终提交,并再次将D设置为分支名称。所以在这种情况下,你得到这个:

HEAD

由于...- A - B - E - F <-- master, origin/master \ \ \ C' - D' <-- HEAD=branch \ C - D <-- ORIG_HEAD 指向的提交通常不会显示,看起来ORIG_HEADC已经消失,副本(D和{{1}是唯一提交的提交。 (尽管如此,C'D'实际上仍在那里,并且会坚持一段时间,直到reflog条目到期。)


考虑到所有这些,一旦你处于“分离的HEAD”状态,C就没有分支名称可以影响。它将移动D,并更改工作目录,但git reset --hard仍将直接指向提交。所以你在一个rebase中间做的任何HEAD充其量都是奇怪的。 (如果你继续下去,他们会弄清楚rebase会发生什么,因为继续一个rebase只是不断增加到当时HEAD点。)

在更正常的情况下(当你在“分支上”时),git reset具有分支的名称。然后(并且只有这样),HEAD可以并确实更改分支名称指向的提交。

您如何判断HEAD将采取哪些行动,以及发生了什么?答案是使用git reset 。如果你不确定发生了什么,git reset就是有帮助的。在过去的几年里,它实际上也在帮助它变得更好! : - )

答案 1 :(得分:7)

如果你在一个分支上,git reset --hard bd53134应该更新分支,并让你离开那个分支。因此,我怀疑你实际上并不在分支机构。

如果这是正确的,可以通过返回分支来解决问题:

git checkout <branch>

然后再次运行您已使用过的git reset命令。