From ca0449fba85d60cfd9a098aecc8a9a92c724b80e Mon Sep 17 00:00:00 2001 From: Greg Pfeil Date: Wed, 1 Oct 2025 11:14:09 -0600 Subject: [PATCH 1/2] Fix `install-hooks.bash` script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I hadn’t realized there were Git hooks, but noticed them when I was adding the Weeder script. So, I documented that they exist, and then fixed the script since it wasn’t working for me. It now works - when run it from anywhere in the repo (not just from two directories down somewhere), - when `core.hooksPath` is set (i.e., `$GIT_DIR/hooks` isn’t the right place), - when run from a worktree (which doesn’t necessarily have its own hooks dir), - when the hooks directory doesn’t exist, and - when the hooks already exist (if you pass `-f`). This also replaces `ln -s` with `cp` so that in case the particular worktree it was run from is renamed or deleted, it doesn’t break the hooks for the repository. --- development.markdown | 8 ++++++++ scripts/install-hooks.bash | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/development.markdown b/development.markdown index ad06ed6ae5..078b4824ca 100644 --- a/development.markdown +++ b/development.markdown @@ -20,6 +20,14 @@ To get cracking with Unison: On startup, Unison prints a url for the codebase UI. If you did step 3 above, then visiting that URL in a browser will give you a nice interface to your codebase. +## Git hooks + +There are some Git hooks provided by Unison. If you want to use them, you can run + +``` bash +./scripts/install-hooks.bash +``` + ## Autoformatting your code with Ormolu We use Ormolu (see [the specific version](./nix/versions.nix)) and CI will add an extra commit, if needed, to autoformat your code. diff --git a/scripts/install-hooks.bash b/scripts/install-hooks.bash index f87c63cd7d..373c8b9d72 100755 --- a/scripts/install-hooks.bash +++ b/scripts/install-hooks.bash @@ -1,9 +1,39 @@ #!/usr/bin/env bash +set -euo pipefail +SCRIPTNAME="$(readlink -f -- "${BASH_SOURCE[0]}")" +SCRIPTDIR="$(dirname -- "$SCRIPTNAME")" -GIT_DIR=$(git rev-parse --git-dir) +function usage { + echo "Usage: $SCRIPTNAME [-f] [-h]" + echo + echo " -f Overwrite hooks if they already exist" + echo " -h Show this usage message" +} + +trap "echo; usage" ERR + +force=("-n") +while getopts ':fh' OPTION; do + case "$OPTION" in + f) + force=("-f") + ;; + h) + usage + exit 0 + ;; + \?) + usage + exit 1 + ;; + esac +done + +hooks_dir=$(git rev-parse --git-path hooks) echo "Installing hooks..." +mkdir -p "$hooks_dir" # this command creates symlink to our pre-commit script -ln -s ../../scripts/pre-commit.bash $GIT_DIR/hooks/pre-commit -ln -s ../../scripts/pre-push.bash $GIT_DIR/hooks/pre-push +cp "${force[@]}" "$SCRIPTDIR/pre-commit.bash" "$hooks_dir/pre-commit" +cp "${force[@]}" "$SCRIPTDIR/pre-push.bash" "$hooks_dir/pre-push" echo "Done!" From 8fef39a22b28587dcd973ecbebc15c262a365ba0 Mon Sep 17 00:00:00 2001 From: Greg Pfeil Date: Wed, 1 Oct 2025 11:55:07 -0600 Subject: [PATCH 2/2] Lint the Git hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bash “strict mode” - address ShellCheck complaints - replace backticks with `$()` - don’t compare against `$?` --- scripts/pre-commit.bash | 11 +++++------ scripts/pre-push.bash | 14 ++++++-------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/scripts/pre-commit.bash b/scripts/pre-commit.bash index cc6b5851ff..0686d8e47d 100755 --- a/scripts/pre-commit.bash +++ b/scripts/pre-commit.bash @@ -1,10 +1,9 @@ #!/usr/bin/env bash +set -euo pipefail -echo "Running pre-commit hook from "`pwd` -./scripts/test.sh +echo "Running pre-commit hook from $(pwd)" -# $? stores exit value of the last command -if [ $? -ne 0 ]; then - echo "Tests must pass before commit!" - exit 1 +if ! ./scripts/test.sh; then + echo "Tests must pass before commit!" + exit 1 fi diff --git a/scripts/pre-push.bash b/scripts/pre-push.bash index 4ea16b3b20..c4b123edfa 100755 --- a/scripts/pre-push.bash +++ b/scripts/pre-push.bash @@ -1,18 +1,16 @@ #!/bin/bash -# Run the following command in the root of your project to install this pre-push hook: -# cp git-hooks/pre-push .git/hooks/pre-push; chmod 700 .git/hooks/pre-push +set -euo pipefail + +# Run `./install-hooks.bash` to install this pre-push hook. # Check if we actually have commits to push -commits=`git log @{u}..` +commits=$(git log "@{u}..") if [ -z "$commits" ]; then exit 0 fi CMD="./scripts/test.sh" -eval $CMD -RESULT=$? -if [ $RESULT -ne 0 ]; then - echo "The git push operation was canceled because \`$CMD\` did not complete successfully." +if ! "$CMD"; then + echo "The git push operation was canceled because ‘$CMD’ did not complete successfully." exit 1 fi -exit 0