Git Pre Commit Hook

November 5, 2025 ยท Tyler Yeager ยท 1 min reading time

To develop my projects, I take advantage of gitโ€™s hooks. The ones I use most commonly are pre-commit and pre-push.

My scripts try to do a quick verification during the pre-commit, a longer and more vigorous test for pre-push.

Just recently I ran into an error during compilation during the CI stage. It would break, but my hooks both showed that there was no error. This would greatly troubling to me, because I had to trust that if both tests passed, that it absolutely work in the CI stage.

After a significant amount of debugging through multiple CI cycles, I found the bug, and it revealed to me why this was happening. In my git repo I had 2 files. One was staged and I wanted to commit and push it. The other was one I had in my working index. Not ready to deploy just yet, a WIP (Work in Progress).

What happened is this WIP file would allow the build to work, but when this change was not pushed and thus not available to the CI git pull, caused the build to fail!

This post helped lead me to a working solution.

Itโ€™s a big hackish, but how it works is like this:

  1. Create a new commit with a comment of โ€œWIPโ€
  2. Stash all existing changes
  3. Restage to the commit before WIP (undo the WIP)
  4. Do my verification steps
  5. Pop the stash and restore the files
.git/hooks/pre-commit
stash_set=false
git commit --no-verify --message "WIP"
git stash --keep-index -u && stash_set=true
git reset --soft HEAD^
# Verification logic
# [...]
if [[ $stash_set == true ]]; then
git stash pop
fi

Switching to Manual

I ran with this for a few days, but I ran into a number of issues. For example, squashing multiple commits caused the pre-commit hook to run and fail, because it couldnโ€™t find the right commit. Initially, I tried to put in some workarounds. However, this did not feel conclusive and prone to unknown errors in the future.

.git/hooks/pre-commit
if [[ "${GIT_REFLOG_ACTION}" =~ "rebase".*"reword" ]]; then
# [...]
fi

So, instead I decided to move it into a command runner. I use just. The stash command verifies there is files that can be stashed, makes a WIP commit, stashes the extra and restores it.

justfile
stash:
#!/usr/bin/env bash
if git diff --cached --quiet; then
git commit --no-verify --message "WIP"
git stash --keep-index -u -m "WIP_STASH"
git reset --soft HEAD^
else
git stash --keep-index -u -m "WIP_STASH"
fi
restore:
git stash list | grep "WIP_STASH" && git stash pop --index

Did you find this interesting?

Consider subscribing ๐Ÿ˜Š

No AI-generated content or SEO garbage.

Unsubscribe anytime