|
| 1 | +#!/usr/bin/env bash |
| 2 | +# |
| 3 | +# Run treefmt on every commit and abort if some files have changed. |
| 4 | +# |
| 5 | +# To install, copy this file to .git/hooks/pre-commit and make sure it's |
| 6 | +# executable. |
| 7 | +# |
| 8 | +set -euo pipefail |
| 9 | + |
| 10 | +# Redirect stdout to stderr |
| 11 | +exec 1>&2 |
| 12 | + |
| 13 | +# Get list of files that will be committed |
| 14 | +mapfile -t commit_files < <(git diff --name-only --cached) |
| 15 | + |
| 16 | +log() { |
| 17 | + echo "treefmt pre-commit: $*" |
| 18 | +} |
| 19 | + |
| 20 | +# If the commit has no files, skip everything as there is nothing to format |
| 21 | +if [[ ${#commit_files} = 0 ]]; then |
| 22 | + log "no files to format" |
| 23 | + exit 0 |
| 24 | +fi |
| 25 | + |
| 26 | +# Will be called at the end |
| 27 | +restore_stash() { |
| 28 | + # Store exit status |
| 29 | + local ret=$? |
| 30 | + # Don't fail on error from now on |
| 31 | + set +e |
| 32 | + # Undo any formatting changes |
| 33 | + git checkout -q . |
| 34 | + # Put bash the staged files |
| 35 | + git stash pop -q |
| 36 | + |
| 37 | + if [[ $ret -gt 0 ]]; then |
| 38 | + log "aborting commit, detected unformatted files" |
| 39 | + fi |
| 40 | + exit "$ret" |
| 41 | +} |
| 42 | + |
| 43 | +# Stash index and work dir, keeping only the to-be-committed changes in |
| 44 | +# the working directory. |
| 45 | +git stash push --quiet --keep-index --message "treefmt pre-commit" |
| 46 | + |
| 47 | +# Install the callback to restore the stash on script exit |
| 48 | +trap restore_stash EXIT |
| 49 | + |
| 50 | +# Run treefmt on the files in the index and record the result. |
| 51 | +# |
| 52 | +# The treefmt cache is not working reliably so we disable it. |
| 53 | +# TODO: use --no-cache instead in treefmt 0.4.0+ |
| 54 | +treefmt --clear-cache --quiet -- "${commit_files[@]}" |
| 55 | + |
| 56 | +# Check if there is a diff |
| 57 | +git diff --name-only --exit-code |
0 commit comments