hooks: refuse master, cap a code commit at 300 lines, require the task ref (V-445)
Two git hooks, tracked in .githooks and wired with core.hooksPath so a fresh clone gets them with one config line. pre-commit refuses master and refuses more than 300 changed lines in non-markdown files. Markdown is exempt because docs land as one batch. This is a commit-time guard, which diff-budget.sh is not: that hook blocks the agent's edits and says nothing when either of us commits. commit-msg requires (V-<id>), not (#<id>). Gitea autolinks # to its own issues, and Vikunja is the tracker. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+30
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Every commit names the Vikunja task it belongs to.
|
||||||
|
#
|
||||||
|
# router: narrow the single-token rule (V-359)
|
||||||
|
#
|
||||||
|
# V- and not #, because Gitea autolinks #359 to a Gitea issue, which is a
|
||||||
|
# different tracker and a wrong link.
|
||||||
|
#
|
||||||
|
# Exempt: merges, reverts, fixup/squash, and the initial commit.
|
||||||
|
|
||||||
|
msg_file=$1
|
||||||
|
subject=$(sed -n '1p' "$msg_file")
|
||||||
|
|
||||||
|
case "$subject" in
|
||||||
|
Merge\ *|Revert\ *|fixup!\ *|squash!\ *|amend!\ *) exit 0 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -f "$(git rev-parse --git-dir)/MERGE_HEAD" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf '%s' "$subject" | grep -qE '\(V-[0-9]+\)$'; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "commit-msg: subject must end with a Vikunja task ref." >&2
|
||||||
|
echo " got: $subject" >&2
|
||||||
|
echo " want: router: narrow the single-token rule (V-359)" >&2
|
||||||
|
echo " No task yet? Create one. Work without a task is work nobody can resume." >&2
|
||||||
|
exit 1
|
||||||
Executable
+30
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Two guards, both bypassable with --no-verify when you mean it.
|
||||||
|
# 1. master is not a working branch.
|
||||||
|
# 2. a code commit stays under 300 changed lines.
|
||||||
|
# Markdown is exempt from the size cap on purpose: docs land as one batch.
|
||||||
|
|
||||||
|
branch=$(git symbolic-ref --short HEAD 2>/dev/null)
|
||||||
|
|
||||||
|
case "$branch" in
|
||||||
|
master|main)
|
||||||
|
echo "pre-commit: refusing to commit on $branch." >&2
|
||||||
|
echo " task start <vikunja-id> # branch off origin/master, write TASK.md" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Added + deleted lines across staged files that are not markdown.
|
||||||
|
# numstat prints "-\t-\t<path>" for binaries; those count 0 and that is fine,
|
||||||
|
# a binary blob is not the kind of diff this cap exists to stop.
|
||||||
|
loc=$(git diff --cached --numstat -- . ':(exclude)*.md' |
|
||||||
|
awk '$1 ~ /^[0-9]+$/ { a += $1 } $2 ~ /^[0-9]+$/ { d += $2 } END { print a + d + 0 }')
|
||||||
|
|
||||||
|
if [ "$loc" -gt 300 ]; then
|
||||||
|
echo "pre-commit: $loc changed lines in non-markdown files, cap is 300." >&2
|
||||||
|
echo " Split it. Each commit should be one reviewable idea." >&2
|
||||||
|
echo " git reset <path> to unstage, or --no-verify if this genuinely cannot split." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user