From 990329cb6d8d70aecea3618a6942ddd673e041c4 Mon Sep 17 00:00:00 2001 From: Oddur Sigurdsson Date: Fri, 11 Sep 2026 02:10:26 -0400 Subject: [PATCH] fix: make the pre-push hook actually guard the default branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exercised with the stdin git supplies, the hook exited 0 on a push to main. default=$(git symbolic-ref ... | sed "s|^$remote/||" || echo main) sed exits 0 even when git failed, so the fallback never fired and default was silently empty — every guard below then compared against "refs/heads/" and matched nothing. Assign first, then test. The same mistake was in scripts/agent's default_branch, where it surfaced as an empty line in doctor. Here it was invisible: a guard that never fires looks exactly like a guard with nothing to catch. Verified both directions — refuses refs/heads/main, and still runs the full check for a feature branch. --- .githooks/pre-push | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/.githooks/pre-push b/.githooks/pre-push index bf2a6e6..91c83c5 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -2,19 +2,22 @@ set -eu remote=$1 -default=$(git symbolic-ref --quiet --short "refs/remotes/$remote/HEAD" 2>/dev/null | sed "s|^$remote/||" || echo main) -while read -r _local_ref local_sha remote_ref _remote_sha; do - case "$remote_ref" in - "refs/heads/$default") - # Allow only the push that creates the branch on the remote. - if git ls-remote --exit-code --heads "$remote" "$default" >/dev/null 2>&1; then - echo "pre-push: $default advances only through a merged pull request" >&2 - exit 1 - fi - ;; - esac - [ "$local_sha" = "0000000000000000000000000000000000000000" ] && continue +# Assign, then test. Piping git into sed and falling back with || cannot work: +# sed succeeds even when git failed, so the fallback never fires and the answer +# is silently empty — which makes every guard below match nothing. +default=$(git symbolic-ref --quiet --short "refs/remotes/$remote/HEAD" 2>/dev/null || true) +default=${default#"$remote/"} +[ -n "$default" ] || default=main + +while read -r _local_ref _local_sha remote_ref _remote_sha; do + if [ "$remote_ref" = "refs/heads/$default" ]; then + # Allow only the push that first creates the branch on the remote. + if git ls-remote --exit-code --heads "$remote" "$default" >/dev/null 2>&1; then + echo "pre-push: $default advances only through a merged pull request" >&2 + exit 1 + fi + fi done exec ./scripts/task check