git rebase -i with squash cannot detach HEAD
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".)
This can also happen if a file that has been marked assume-unchanged
or skip-worktree
has also been modified:
- You won't see the changes in
git status
. - You might be used to
git rebase
autostashing all changes for you but it doesn't seem to deal with these ones (as of Git 2.21 and no mention of it changing in subsequent release notes).
You can list such files if you want confirm this but the error message should already alert you to something strange because it will show a filename that doesn't appear in git status
.