#!/bin/sh # # Reindent staged C sources to the canonical style before the commit is made. # See AGENTS.md -> "Coding Style". # # Enable with: # git config core.hooksPath scripts/hooks # Bypass a single commit with `git commit --no-verify`. # # The hook checks the *staged* content, not the working tree, so what gets # committed is what was verified. When a file needs reindenting it is fixed in # the working tree and re-staged -- but only when the working tree and the index # agree for that file. If they disagree (a partial `git add -p`), re-staging # would sweep unstaged work into the commit, so the hook stops and asks you to # do it yourself. set -eu root=$(git rev-parse --show-toplevel) reindent="$root/scripts/reindent.sh" # Leave conflict resolution alone. if [ -e "$root/.git/MERGE_HEAD" ]; then exit 0 fi if [ ! -x "$reindent" ]; then echo "pre-commit: $reindent missing or not executable; skipping style check" >&2 exit 0 fi # Without Emacs the canonical style cannot be applied or even checked. Warn # rather than block: a hook that fails closed on a missing optional tool just # teaches everyone to pass --no-verify. if ! command -v emacs >/dev/null 2>&1; then echo "pre-commit: emacs not found; skipping reindent (see AGENTS.md)" >&2 exit 0 fi staged=$(git diff --cached --name-only --diff-filter=ACMR \ | grep -E '^(src|include|tests|util)/.*\.[ch]$' \ | grep -v -x -F 'include/akgl/SDL_GameControllerDB.h' || true) if [ -z "$staged" ]; then exit 0 fi tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT INT TERM # Reindent a copy of each file's staged content and see whether it moves. needs='' for f in $staged; do copy="$tmp/$(printf '%s' "$f" | tr '/' '_')" git show ":$f" >"$copy" cp "$copy" "$copy.orig" if ! "$reindent" "$copy" >/dev/null 2>&1; then echo "pre-commit: reindent failed on $f; commit aborted" >&2 exit 1 fi if ! cmp -s "$copy" "$copy.orig"; then needs="$needs $f" fi done if [ -z "$needs" ]; then exit 0 fi # Refuse to touch anything if even one file is partially staged. blocked='' for f in $needs; do if ! git diff --quiet -- "$f"; then blocked="$blocked $f" fi done if [ -n "$blocked" ]; then echo "pre-commit: these files need reindenting but have unstaged changes," >&2 echo "so re-staging them would pull unstaged work into the commit:" >&2 for f in $blocked; do echo " $f" >&2; done echo >&2 echo "Reindent and stage them yourself, then commit again:" >&2 echo " scripts/reindent.sh$(for f in $blocked; do printf ' %s' "$f"; done)" >&2 echo " git add$(for f in $blocked; do printf ' %s' "$f"; done)" >&2 exit 1 fi # Safe: for every file needing work, the index and working tree agree. # shellcheck disable=SC2086 "$reindent" $needs # shellcheck disable=SC2086 git add $needs echo "pre-commit: reindented and re-staged:" >&2 for f in $needs; do echo " $f" >&2; done exit 0