我在分支机构工作,需要撤消一些提交。所以我做了
$> git reset --hard bd53134
这具有预期的效果,除了我现在有一个独立的头:(
$> git status
HEAD detached at bd53134
我该如何解决这个问题?
答案 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} }),然后可能会执行一个D
和git checkout master
来自“远程git pull
”的提交E
和F
。然后,您使用origin
返回branch
(因此git checkout branch
)。
然后,您决定应在HEAD=branch
之上重新定位C
和D
,从而提供更多线性提交序列:
F
(我稍后会展示为什么...- A - B - E - F <-- master, origin/master
\
C' - D' <-- HEAD=branch
和C'
代替D'
和C
。)所以你运行D
到“移动“将git rebase master
和C
提交到D
的提示。
Rebase实际上并没有移动提交。它的作用是复制一些现有的提交,使新的“做同样的事情”并且“同样好”(我们希望!)。因此,rebase保持master
和C
。它使用一个特殊标签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}}但仍然分离了D
,HEAD
。但是,这次出现问题:补丁不适用:
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_HEAD
和C
已经消失,副本(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
命令。