我在一个分支中工作,需要撤消几个提交。所以我做到了
$> git reset --hard bd53134
这有了预期的效果,只是我现在有了一个独立的脑袋:(
$> git status
HEAD detached at bd53134
我该怎么解决?
最佳答案
看起来你可能还在胡思乱想,所以这里有一点背景。你在一篇评论中提到你开始了一个git rebase
并且总是抱怨。(这真的应该是最初问题的一部分。)
首先注意:git rebase --continue
可以正常(“未分离”?)或“分离”。“normal”HEAD
只包含一个分支名称。如果您是“on branchHEAD
”,master
只会说“on branch master”。“分离的头”听起来像是法国大革命的东西,它由一个原始的sha-1提交id组成。我喜欢在下面的图形中写附加的头,作为HEAD
,然后显示分支指向的位置,使用箭头指向一个特定的提交。
在开始一个rebase之前,您有一个commit图,它可能如下所示:
...- A - B - E - F <-- master, origin/master
\
C - D <-- HEAD=branch
在本例中,我假设您从
HEAD=branch
执行了git checkout -b branch
操作,并在master
上执行了一些提交操作(创建branch
和C
),然后可能执行了D
和git checkout master
操作,这将从“remotegit pull
执行提交操作E
和F
。然后用origin
返回branch
(因此git checkout branch
)。然后,您决定应在
HEAD=branch
的基础上重新建立C
和D
的基础,给出更为线性的提交序列:...- A - B - E - F <-- master, origin/master
\
C' - D' <-- HEAD=branch
(稍后我将展示为什么这些是
F
和C'
而不是D'
和C
)因此运行D
将提交和git rebase master
移动到C
的顶端。rebase实际上并不移动提交。它所做的是复制一些现有的提交,做出新的“做同样的事情”,“也一样好”(我们希望!)因此,rebase保持
D
和master
左右。它使用一个特殊的标签C
,来跟踪commitD
(以及一堆额外的ORIG_HEAD
文件来跟踪整个rebase操作的所有进度这些文件实际上是git如何知道rebase是“进行中”的)。rebase通过添加这个
D
和“分离头”开始这个过程。它将“分离头”设置为直接指向rebase的目标(在本例中为commit.git/rebase-apply/
)。(通过翻来翻去,似乎文档中也有关于它重置分支的内容。但这在旧版本的git中可能有所不同;我认为文档在某一点上是准确的)。...- A - B - E - F <-- master, origin/master
\ \
\ \...... HEAD [detached]
\
C - D <-- ORIG_HEAD, branch
然后,对于每个提交(
ORIG_HEAD
和F
这里),它获取在提交中所做的更改,并尝试将这些相同的更改应用于C
提交。如果一切顺利,它通常会用与旧提交相同的消息进行新的提交。这就是承诺:...- A - B - E - F <-- master, origin/master
\ \
\ C'..... HEAD [detached]
\
C - D <-- ORIG_HEAD, branch
成功地将
D
应用到HEAD
以使C'
退出C
后,rebase命令继续尝试将F
应用到新的(但仍分离的)C'
,F
。但是,这次出现了问题:修补程序不适用: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".
此时,您的提交图看起来就像我在上面绘制的(有些混乱)图。
作为rebase prints,您可以:
手动解决问题并
D
,或选择用
HEAD
删除提交(C'
,在本例中)或用
git rebase --continue
退出这一切。选择最后一个选项,告诉rebase停止rebase尝试,将
D
恢复原样,并删除“rebase in progress”状态/跟踪文件。这还将删除整个新提交(但尚未标记为分支)链。(从技术上讲,他们仍然在那里,在重新登录。通常你不会看到他们。)执行第一个(“手动解决”)或选择中间(“跳过”)选项,让rebase继续前进。假设您解决了问题并
git rebase --skip
。一旦rebase用完提交,并且最后一个提交是git rebase --abort
,它就会将分支名称移到最后一个提交,并再次将HEAD
设置为分支名称。在这种情况下,你会得到:...- A - B - E - F <-- master, origin/master
\ \
\ C' - D' <-- HEAD=branch
\
C - D <-- ORIG_HEAD
由于
git rebase --continue
所指向的提交通常不会显示,因此看起来D
和HEAD
已不存在,而副本(ORIG_HEAD
和C
)是仅存的提交。(与往常一样,D
和C'
实际上仍在其中,并将停留一段时间,直到重新登录条目过期。)考虑到所有这些,一旦您处于“分离的头”状态,
D'
就没有分支名称可影响。它将移动C
,并更改工作目录,但D
仍将直接指向提交。所以,你在一个回扣中间做的任何事情,嗯,充其量也很奇怪。(如果你继续这样做,他们会处理rebase发生的事情,因为继续一个rebase只会增加到当时git reset --hard
点的位置。)在更正常的情况下(当您“在分支上”时),
HEAD
具有分支的名称。然后(并且只有在那时),HEAD
可以并且确实将分支名称指向的提交更改为。如何判断
git reset
将采取哪些行动,以及发生了什么?答案是使用HEAD
。如果你不确定发生了什么,HEAD
是用来帮助你的。在过去的几年里,它在实际帮助方面也变得更好了!:-)关于git - git:'git reset后分离的头--hard bd53134,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19923958/