I am using "husky": "^7.0.4"
.
My team squashes their commits before opening a PR.
I have a pre-commit
file to automate this workflow. Every other time I run the commit function, the pre-commit flow works perfectly. So the 1st, 3rd, 5th, etc. works. The 2nd, 4th, 6th, etc time prints this error
fatal: cannot lock ref 'HEAD': is at 766hdjoXXX but expected 766e11XXX
I thought it might be because I wasn't changing the file, however when I tried changing something, that didn't work either(it succeeds and fails every other time regardless). Any idea what's wrong?
Here is the pre-commit
file:
read -n1 -p "Do you want to squash commits? [n/Y]" SHOULD_SQUASH < /dev/tty
case $SHOULD_SQUASH in
n|N)
echo
echo Skipping squash, now linting files...
;;
y|Y)
[ -z "$SQUASH_BRANCH" ] && SQUASH_BRANCH=develop
branch=$(git symbolic-ref HEAD)
echo
echo Squashing all commits from $branch
git reset $(git merge-base $SQUASH_BRANCH $branch)
echo ------SUCCESS!------
echo Commits successfully squashed.
git add .
echo Added all files successfully.
;;
*)
echo
echo Skipping squash, now linting files...
;;
esac
npx pretty-quick --staged
npm run lint
The squash function is from a custom function, that works with no problem, we created that lives in .zshrc
.
Pre-commit files in general should not use git reset
and git add
. It is possible to make this work sometimes, but you get odd effects, including the one you're seeing (and sometimes worse ones). A pre-commit script should limit itself to testing whether the commit is OK, and if so, exiting zero; if not, the script should exit nonzero, without attempting to make any changes.1
Instead of calling your script .git/pre-commit
and invoking it with git commit
, call it makecommit
and invoke it as makecommit
. Or, call it git-c
and invoke it as git c
. Have the script do its thing—including run npm lint
—and if all looks good, have it run git commit
. You won't need a pre-commit hook at all, but if you like, you can have one that reads as follows:
[ "$RUN_FROM_OUR_SCRIPT" = yes ] && exit 0
echo "don't run git commit directly, run our script instead"
exit 1
Then instead of just git commit
, have your script do:
RUN_FROM_OUR_SCRIPT=yes git commit
which will set the variable that the pre-commit hook tests to make sure git commit
was run from your script.
Note that you will no longer need to redirect the read
from /dev/tty
. (You probably should also consider using git reset --soft
, and/or verifying the that index content matches the working tree content.)
1If you like to live dangerously, and really want to have a script that can update files, make sure that $GIT_INDEX_FILE
is unset or set to .git/index
, to make sure you have not been invoked as git commit --only
.