git rebase -i使用squash无法分离HEAD

11

使用最新的git(2.1.0.24),每当我尝试git rebase -isquash一些提交时,squash无法detach HEAD状态。我期望它能够将提交合并并像预期的那样放回我的分支上。我的工作树中没有未暂存的文件、更改或任何存储内容。为什么会这样?

> [master] » git rebase -i HEAD~3

(我压缩了几个提交)...

pick c9e9b62 Fixes super important bug #123. 
squash c0dc9f9 wip 
pick 5385a37 wip2

# Rebase fb83e59..5385a37 onto fb83e59 

然后它就给了我

Note: checking out 'c9e9b62'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at c9e9b62... Fixes super-important bug #123.
could not detach HEAD

似乎成功地进行了变基,但出于某种原因无法将我放回分支。

> [c9e9b62] » git rebase --continue
No rebase in progress?

重塑尝试之前的git图形日志:

* 5385a37 (HEAD, master) wip2
* c0dc9f9 wip
* c9e9b62 Fixes super-important bug #123.
* ff80ed9 random commit msg
* 1f407d5 random commit msg
...
* ef106db random commit msg
*   6c244ef Merge branch 'sentences'
|\
| * a641cbf (origin/sentences) random commit msg
| * bfe8eae random commit msg
| ...

尝试rebase后的git图形日志:

* c9e9b62 (HEAD) Fixes super-important bug #123.
* ff80ed9 random commit msg
* 1f407d5 random commit msg
...
* ef106db random commit msg
*   6c244ef Merge branch 'sentences'
|\
| * a641cbf (origin/sentences) random commit msg
| * bfe8eae random commit msg
| ...

你遇到了冲突吗?你执行了 git rebase --continue 命令吗?还是执行了 --abort 命令? - Edward Thomson
似乎没有任何冲突。(更新问题,当我使用--continue时会发生什么) - atp
1
@JoëlSalamin,添加了最近的图形日志提交。这有帮助吗? - atp
你的“master”在你的尝试后还在图表上吗?我在你的图表示例中再也看不到它了。 - Joël Salamin
@JoëlSalamin,不,它不存在。我认为由于错误的存在,这是有意义的,因为它让我将HEAD指向提交而不是分支。 - atp
显示剩余8条评论
4个回答

18

这条消息无法分离HEAD来自交互式变基脚本,具体位置在这里:

GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
output git checkout $onto || die_abort "could not detach HEAD"
git update-ref ORIG_HEAD $orig_head
do_rest

有趣的是,这里的git checkout $onto步骤似乎已成功:在失败之前,您得到了:

HEAD is now at c9e9b62... Fixes super-important bug #123.

输出结果来自于此处发生的 git checkout。然后,在明显成功之后,git checkout却似乎以失败结束并退出了非零状态。这导致调用了 die_abort,从而终止了rebase尝试。

现在,文档声称后检出钩子无法影响 git checkout 结果。

然而,在 源代码 中,在 switch_branches 底部附近,我们有:

    ret = post_checkout_hook(old.commit, new->commit, 1);
    free(path_to_free);
    return ret || writeout_error;

post_checkout_hook 运行 Git 的 post-checkout 钩子,并获取其退出码。因此,git checkout 看起来有两种方式返回失败状态:一是写入树时出错(例如磁盘已满),二是存在 post-checkout 钩子且它以非零值退出。后者似乎更有可能。(我已经测试过了,的确会导致检出操作“失败”。由于源代码使用了 ||,钩子中的任何非零退出都会变成 git checkout 本身的退出状态为 1。)

您是否有 post-checkout 钩子?如果有,它是用来做什么的?

(目前还不清楚是文档有误还是 git checkout 命令有误,但至少其中一个是有误的。我认为可能是文档有误,应该更像是“不能影响 git checkout 将要写入的文件,但可以使命令本身返回失败状态”。)


1
非常感谢。我有一个后检出钩子,它从ctags中删除错误消息:ctags -R maindir 2>&1 | grep -v "ignoring null"。退出状态确实是1grep手册说:“如果找到了选定的行,则退出状态为0,如果未找到,则为1”,因此即使它匹配并剥离“ignoring null”消息,也会报告1,因为-v反转了其功能!所以我在钩子中添加了exit 0;,现在重新基础工作正常:成功地重新基础和更新了refs/heads/master。没有你的帮助,我永远不会解决这个问题。谢谢! - atp
看起来又是 Git 钩子文档不好的情况!当我第一次开始编写 Git 钩子(在 Git 1.5.x 的时代),它真的很糟糕。现在也不太好... - torek
感谢您的帮助。如果没有您的帮助,我可能会花很长时间才能弄清楚这个问题。 - Tim D
在我提交检出后(运行yarn install),加上exit 0就解决了这个问题。谢谢@ash。 - Moak

1

如果一个已被标记为assume-unchangedskip-worktree的文件也被修改了,这种情况也会发生:

  1. 你在git status中看不到更改。
  2. 你可能习惯于使用git rebase自动为你保存所有更改,但它似乎无法处理这些更改(截至Git 2.21,并未在后续发布说明中提到有任何更改)。

如果您想确认此类文件,请列出这些文件,但错误消息应该已经提示您存在某些奇怪的问题,因为它将显示一个在git status中未出现的文件名。


0

正如之前的评论所暗示的那样,也许您有一个 post-checkout 钩子,它会产生非零退出。我有一个钩子,在最后一个命令可能基于 if 开关具有不同的退出:

if false
  command-that-exits-with 0
else
  command-that-exists-with 5
  # hook will exit with 5
end

# EOF

尽管我的脚本条件未满足仍然能够正常运行。确实如此:

$ .git/hooks/post-checkout
doing stuff!
$ echo $?
5

我在脚本末尾添加了exit 0,就完成了。


0
另一个可能的原因是如果在提交之间移动会创建一些不一致性...例如,假设您有:
HASH2 change line in file b
HASH1 rename file a to b

当然,HASH1 是最旧的。如果你试图在 HASH1 之前移动 HASH2,你会得到 could not detach HEAD

当然,在一个更长的实际例子中,有多个提交和压缩被重新设置,你可能会忽略这种不一致性!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接