Optional githook behaving like optional
I'm trying to use this meaning in my workflow how post-merge
and post-checkout
git hooks.
#!/usr/bin/env bash
# MIT Β© Sindre Sorhus - sindresorhus.com
# git hook to run a command after `git pull` if a specified file was changed
# Run `chmod +x post-merge` to make it executable then put it into `.git/hooks/`.
changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
check_run() {
echo "$changed_files" | grep --quiet "$1" && eval "$2"
}
# Example usage
# In this example it used to run `npm install` if package.json changed
check_run package.json "npm install"
This means only run npm install if the file package.json
has changed.
However, on all machines I have tried this. The npm install command runs regardless of whether package.json has been modified or not.
To test this, I create a new branch on my current commit and then checkout it, thereby triggering a post-checkout
git hook . I didn't expect to npm install
be launched because it package.json
won't change.
Visual Proof (note the npm warning text):
source to share
TL; DR
Use another hook after checking which uses $1
instead ORIG_HEAD
. (Or, check the number of arguments to decide if you will be called as a post-checkout or a post-merge hook to get the same effect. Or, if you know reflogs are always on, use HEAD@{1}
to get the previous value HEAD
.)
Discussion
Using ORIG_HEAD
in a post-merge hook makes sense because it git merge
sets ORIG_HEAD
to the commit that was current before the merge. (If the merge was a true merge rather than fast forward, the commit identified MERGE_HEAD
and the commit identified with HEAD^1
are necessarily identical. However, if the merge was fast forward, then only the MERGE_HEAD
reflog will be able to find the previous hash that was stored in HEAD
before the merge. .)
ORIG_HEAD
Post-validation cache usage , however, is clearly flawed because it git checkout
doesn't install ORIG_HEAD
. This means that ORIG_HEAD
even if it exists at all, it actually indicates a random occurrence. (Of course, in fact it permits everything that has been recorded in it any, last updated command: git merge
, git rebase
or any other command that writes to ORIG_HEAD
. But the point here is that it does not have any relation to the fixing, which was current before discharge.) Quest after check :
three parameters are given: ref of the previous HEAD, a link to the new HEAD (which may or may not have changed), and a flag indicating whether the check was output checkout (changing branches, flag = 1) or checking a file (getting a file from an index, flag = 0). This hook cannot affect the git output.
(the last sentence is not entirely correct. Although the post-check hook cannot stop the check when the index and working tree are updated, it can overwrite various data in the working tree or index, and if it issues a crash status, it calls itself git checkout
to create a crash status .)
All this means that you need to perform another action in the cache after checking: use the $1
first parameter to get the hash id of the previous one HEAD
. Note that in exotic cases, the 1 on the initial git clone
starts the hook after the check, so there $1
may be null-ref. (I'm now curious what it is when you use git checkout --orphan
and then don't create a new branch. Looks like $1
null-ref will be here too.)
1 The only way to get the post test hook to launch on git clone
is to install the git clone
alignment hook after testing. This is usually not possible, but it can be done by pointing your git to your own template directories which have actual hooks, not just hook patterns.
source to share