Skip to content

Commit fdb2a77

Browse files
WomB0ComB0claude
andcommitted
fix(git-hooks): canonical polish from org-wide review
Three related fixes across pre-push and commit-msg, uncovered by gemini/coderabbit review on crates#47, crates#48, dev#4, npm#31: - pre-push: guard the force-push loop with [ -n "$PUSH_REFS" ] and skip iterations with empty local_sha. Previous here-doc refactor fed a trailing newline through the loop, causing `git merge-base` to fire with empty args and falsely reject pushes without ref input. - commit-msg: move the WIP/fixup/squash guard *before* the format check so a user on main gets the branch-specific "WIP not allowed on main" message instead of the generic "Invalid format" error. Previously dead code because WIP messages never matched the Conventional Commits regex. - commit-msg: tighten the ticket-prefix regex from [A-Z]+ to [A-Z]{2,} for consistency with prepare-commit-msg, which only prepends 2+ char prefixes. Also mention the Conventional Commits ! marker in the error hint so users know `feat!:` is accepted. Propagates to crates templates + npm via the open PRs rebasing or re-syncing from this baseline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 21c7a77 commit fdb2a77

File tree

2 files changed

+31
-20
lines changed

2 files changed

+31
-20
lines changed

scripts/git-hooks/commit-msg

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,33 @@ INPUT_FILE="${1:-}"
1313
PATTERN="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .+$"
1414

1515
FIRST_LINE=$(head -1 "$INPUT_FILE")
16-
SUBJECT=$(sed 's/^\[[A-Z][A-Z]*-[0-9]*\][[:space:]]*//' <<<"$FIRST_LINE")
17-
18-
if ! grep -qE "$PATTERN" <<<"$SUBJECT"; then
19-
echo "Error: Invalid commit message format."
20-
echo "Expected: type(scope): subject"
21-
echo "Examples:"
22-
echo " feat(core): add new feature"
23-
echo " fix(ui): fix button color"
24-
exit 1
25-
fi
16+
# Ticket-prefix regex matches what prepare-commit-msg prepends ({2,} chars).
17+
SUBJECT=$(sed -E 's/^\[[A-Z]{2,}-[0-9]+\][[:space:]]*//' <<<"$FIRST_LINE")
2618

19+
# WIP / fixup! / squash! guard runs *before* the format check so users get
20+
# a branch-specific error message on main/master instead of the generic
21+
# "Invalid commit message format".
2722
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "")
2823
case "$BRANCH" in
2924
main|master)
30-
if grep -qiE "^(\[[A-Z]+-[0-9]+\] )?(fixup!|squash!|wip[: ])" <<<"$FIRST_LINE"; then
25+
if grep -qiE "^(\[[A-Z]{2,}-[0-9]+\] )?(fixup!|squash!|wip[: ])" <<<"$FIRST_LINE"; then
3126
echo "Error: fixup!/squash!/WIP commits are not allowed on $BRANCH."
3227
echo "Create a feature branch instead."
3328
exit 1
3429
fi
3530
;;
3631
esac
3732

33+
if ! grep -qE "$PATTERN" <<<"$SUBJECT"; then
34+
echo "Error: Invalid commit message format."
35+
echo "Expected: type(scope)(!): subject"
36+
echo "Examples:"
37+
echo " feat(core): add new feature"
38+
echo " feat!: remove deprecated API (breaking change marker)"
39+
echo " fix(ui): fix button color"
40+
exit 1
41+
fi
42+
3843
LOCAL_HOOK="$(git rev-parse --show-toplevel)/.git-hooks/local-commit-msg"
3944
if [ -x "$LOCAL_HOOK" ]; then
4045
exec "$LOCAL_HOOK" "$@"

scripts/git-hooks/pre-push

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,24 @@ fi
2525
# ── Force-push guard on main/master ─────────────────────────────────────────
2626
case "$BRANCH" in
2727
main|master)
28-
while read -r _local_ref local_sha _remote_ref remote_sha; do
29-
if [ "$remote_sha" != "0000000000000000000000000000000000000000" ] && \
30-
[ "$local_sha" != "0000000000000000000000000000000000000000" ]; then
31-
if ! git merge-base --is-ancestor "$remote_sha" "$local_sha" 2>/dev/null; then
32-
echo "❌ Force push to $BRANCH is not allowed."
33-
echo " Override with: git push --no-verify"
34-
exit 1
28+
# Only iterate when git actually gave us refs — an empty $PUSH_REFS
29+
# would otherwise feed one blank line through the heredoc and trip
30+
# the guard.
31+
if [ -n "$PUSH_REFS" ]; then
32+
while read -r _local_ref local_sha _remote_ref remote_sha; do
33+
[ -z "$local_sha" ] && continue
34+
if [ "$remote_sha" != "0000000000000000000000000000000000000000" ] && \
35+
[ "$local_sha" != "0000000000000000000000000000000000000000" ]; then
36+
if ! git merge-base --is-ancestor "$remote_sha" "$local_sha" 2>/dev/null; then
37+
echo "❌ Force push to $BRANCH is not allowed."
38+
echo " Override with: git push --no-verify"
39+
exit 1
40+
fi
3541
fi
36-
fi
37-
done <<EOF
42+
done <<EOF
3843
$PUSH_REFS
3944
EOF
45+
fi
4046
;;
4147
esac
4248

0 commit comments

Comments
 (0)