ash ash - 3 months ago 24
Git Question

git rebase -i with squash cannot detach HEAD

Using the latest git (

2.1.0.24
), whenever I try to
git rebase -i
to
squash
some commits, the squash cannot
detach HEAD
state. I expect it to squash the commits and put me back on my branch as I expected. There are no unstaged files, changes in my working tree, or anything in the stash. Why is it doing this?

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


(I squash a few commits)...

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

# Rebase fb83e59..5385a37 onto fb83e59


(Then it gives me)

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


It appears to rebase successfully, but for some reason won't put me back on the branch.

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


git graph log BEFORE the rebase attempt:

* 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
| ...


git graph log AFTER the rebase attempt:

* 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
| ...

Answer

The message could not detach HEAD comes from the interactive rebase script, specifically right here:

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

The curious part here is that the git checkout $onto step appears to have succeeded: right before the failure, you got:

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

as output, and that's from the git checkout that happened here. Then, after apparently succeeding, git checkout apparently exited non-zero as if it had failed. This invoked die_abort which terminated the rebase attempt.

Now, the documentation claims that a post-checkout hook

cannot affect the outcome of git checkout.

However, in the source, near the bottom of switch_branches, we have:

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

where post_checkout_hook runs the post-checkout hook and grabs its exit code. So there appear to be two ways for git checkout to return a failure status here: either there's an error writing the tree (e.g., the disk has filled up), or you have a post-checkout hook and it is exiting non-zero. The latter seems more likely. (And, I tested this and it does in fact cause the checkout to "fail". Since the source uses ||, any nonzero exit in the hook turns into an exit status of 1 for git checkout itself.)

Do you have a post-checkout hook? If so, what does it do?

(It's not clear which is wrong here, the documentation or the git checkout command, but at least one is wrong. I'd say probably the documentation, which should say something more like "cannot affect the files that git checkout will write, but can make the command itself return a failure status".)

Comments