TL;DR
Use a different post-checkout hook, that uses $1
instead of ORIG_HEAD
. (Or, check the number of arguments to decide whether you are being invoked as the post-checkout or post-merge hook, to get the same effect. Or, if you know that reflogs are always enabled, use HEAD@{1}
to get the previous value of HEAD
.)
Discussion
Using ORIG_HEAD
in a post-merge hook makes sense, because git merge
sets ORIG_HEAD
to the commit that was current before the merge. (If the merge was a true merge, rather than a fast-forward, the commit identified by MERGE_HEAD
and the commit identified by HEAD^1
are necessarily identical. If the merge was a fast-forward, however, only MERGE_HEAD
and the reflog will be able to locate the previous commit hash that was stored in HEAD
before the merge.)
Using ORIG_HEAD
in a post-checkout hook, however, is blatantly wrong, because git checkout
does not set ORIG_HEAD
. This means that if ORIG_HEAD
even exists at all, it effectively points to some random commit. (Of course, it actually resolves to whatever commit was left in it by whatever command last updated it: git merge
, git rebase
, or any other command that writes to ORIG_HEAD
. But the point here is that it does not have any relationship to the commit that was current before the checkout.) A post-checkout hook:
is given three parameters: the ref of the
previous HEAD, the ref of the new HEAD (which may or may not have
changed), and a flag indicating whether the checkout was a branch
checkout (changing branches, flag=1) or a file checkout (retrieving a
file from the index, flag=0). This hook cannot affect the outcome of
git checkout.
(That last sentence is not quite right. Although the post-checkout hook cannot stop checkout from having updated the index and work-tree, it can overwrite various work-tree or index contents, and if it produces a failure exit status, it causes git checkout
itself to also produce a failure exit status.)
What this all means is that you need to take a different action in a post-checkout hook: use $1
, the first parameter, to get the hash ID of the previous HEAD
. Note that in exotic cases,1 the post-checkout hook is run on the initial git clone
, so $1
can be the null-ref. (I'm now curious as to what it is when you use git checkout --orphan
and then don't create the new branch, as well. It seems likely that $1
will be the null-ref here too.)
1The only way to get a post-checkout hook to run on git clone
is to have git clone
install the post-checkout hook. This is normally impossible, but can be done by pointing your Git to your own template directories that have actual hooks instead of just sample hooks.