#!/bin/sh # pre-commit: clang-format the C lines this commit touches. # # Scoped to *changed lines* via git-clang-format, NOT whole files: the # codebase deliberately packs multiple statements per line (opcode tables, # ALU helpers) and a full-file reformat would destroy that. New/edited # lines converge on .clang-format style; untouched history stays intact. # # Enable once per clone: git config core.hooksPath hooks # Bypass for one commit: git commit --no-verify # staged C files (added/copied/modified/renamed) staged=$(git diff --cached --name-only --diff-filter=ACMR -- '*.c' '*.h') [ -z "$staged" ] && exit 0 if ! command -v git-clang-format >/dev/null 2>&1; then echo "pre-commit: git-clang-format not found (install clang-format)." >&2 echo "pre-commit: bypass with: git commit --no-verify" >&2 exit 1 fi # git-clang-format --staged applies fixes to the WORKTREE, so we must re-add # the files afterwards. That is only safe when index == worktree for every # staged C file; refuse partially-staged files instead of mixing changes. partial=$(git diff --name-only -- $staged) if [ -n "$partial" ]; then echo "pre-commit: partially staged C files (index != worktree):" >&2 printf ' %s\n' $partial >&2 echo "pre-commit: stage them fully (git add) or bypass with --no-verify." >&2 exit 1 fi out=$(git clang-format --staged --quiet --extensions c,h 2>&1) rc=$? if [ $rc -ge 2 ]; then # real error (1 = "changes made") echo "pre-commit: git-clang-format failed:" >&2 echo "$out" >&2 exit 1 fi if [ $rc -eq 1 ]; then git add -- $staged echo "pre-commit: clang-formatted changed lines in:" >&2 printf ' %s\n' $staged >&2 fi exit 0