From bbb5689b1f25e45185d3d0e6ee74385d4801534b Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Sat, 4 Apr 2026 23:03:06 -0500 Subject: [PATCH] fix: address review feedback (#181) - pre-commit: guard ruff --fix + git add with git stash --keep-index so partial-staging (git add -p) workflows are not silently broken - pre-commit: use -z / xargs -0 for null-delimited filename handling - install-hooks.sh: update echo messages to reflect auto-fix behaviour Co-Authored-By: Claude Sonnet 4.6 --- .githooks/install-hooks.sh | 16 ++++++++-------- .githooks/pre-commit | 22 ++++++++++++++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/.githooks/install-hooks.sh b/.githooks/install-hooks.sh index 39da684..61874fd 100755 --- a/.githooks/install-hooks.sh +++ b/.githooks/install-hooks.sh @@ -6,8 +6,8 @@ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) if [ -z "$REPO_ROOT" ]; then - echo "Error: Not in a git repository" - exit 1 + echo "Error: Not in a git repository" + exit 1 fi HOOKS_DIR="$REPO_ROOT/.githooks" @@ -16,16 +16,16 @@ GIT_HOOKS_DIR="$REPO_ROOT/.git/hooks" echo "Installing git hooks..." if [ -f "$HOOKS_DIR/pre-commit" ]; then - cp "$HOOKS_DIR/pre-commit" "$GIT_HOOKS_DIR/pre-commit" - chmod +x "$GIT_HOOKS_DIR/pre-commit" - echo "Installed pre-commit hook" + cp "$HOOKS_DIR/pre-commit" "$GIT_HOOKS_DIR/pre-commit" + chmod +x "$GIT_HOOKS_DIR/pre-commit" + echo "Installed pre-commit hook" else - echo "pre-commit hook not found in $HOOKS_DIR" + echo "pre-commit hook not found in $HOOKS_DIR" fi echo "" echo "The pre-commit hook will:" -echo " - Run ruff lint checks" -echo " - Block commits on syntax errors or lint failures" +echo " - Auto-fix ruff lint violations (unused imports, formatting, etc.)" +echo " - Block commits only on truly unfixable issues" echo "" echo "To bypass in emergency: git commit --no-verify" diff --git a/.githooks/pre-commit b/.githooks/pre-commit index a40a8b3..a05a3dc 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -13,19 +13,33 @@ NC='\033[0m' REPO_ROOT=$(git rev-parse --show-toplevel) cd "$REPO_ROOT" -STAGED_PY=$(git diff --cached --name-only --diff-filter=ACM -- '*.py') +STAGED_PY=$(git diff --cached --name-only --diff-filter=ACM -z -- '*.py') if [ -z "$STAGED_PY" ]; then exit 0 fi echo "ruff check on staged files..." +# Stash unstaged changes so ruff only operates on staged content. +# Without this, ruff --fix runs on the full working tree file (staged + +# unstaged), and the subsequent git add would silently include unstaged +# changes in the commit — breaking git add -p workflows. +STASHED=0 +if git stash --keep-index -q 2>/dev/null; then + STASHED=1 +fi + # Auto-fix what we can, then re-stage the fixed files -echo "$STAGED_PY" | xargs ruff check --fix --exit-zero -echo "$STAGED_PY" | xargs git add +printf '%s' "$STAGED_PY" | xargs -0 ruff check --fix --exit-zero +printf '%s' "$STAGED_PY" | xargs -0 git add + +# Restore unstaged changes +if [ $STASHED -eq 1 ]; then + git stash pop -q +fi # Now check for remaining unfixable issues -echo "$STAGED_PY" | xargs ruff check +printf '%s' "$STAGED_PY" | xargs -0 ruff check RUFF_EXIT=$? if [ $RUFF_EXIT -ne 0 ]; then