Enhancements — Git Hook Collection¶
Extend the hook collection with more checks and better developer experience.
Enhancement 1 — prepare-commit-msg Auto-Formatting¶
Auto-prepend the branch name as a scope or ticket ID:
#!/usr/bin/env bash
# prepare-commit-msg — Prepend branch name / ticket ID to message
MSG_FILE="$1"
COMMIT_SOURCE="${2:-}"
# Don't modify merge/squash/amend commits
[[ "$COMMIT_SOURCE" =~ ^(merge|squash|commit)$ ]] && exit 0
# Extract ticket from branch name: feature/JIRA-123-description → JIRA-123
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "")
TICKET=$(echo "$BRANCH" | grep -oE '[A-Z]+-[0-9]+' | head -1)
if [[ -n "$TICKET" ]]; then
CURRENT=$(cat "$MSG_FILE")
# Only prepend if not already present
if ! grep -q "$TICKET" "$MSG_FILE"; then
echo "${TICKET}: ${CURRENT}" > "$MSG_FILE"
fi
fi
Enhancement 2 — post-commit Notification¶
Print a summary after a successful commit:
#!/usr/bin/env bash
# post-commit — Show a summary after each commit
HASH=$(git log -1 --format="%h")
SUBJECT=$(git log -1 --format="%s")
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "detached")
FILES=$(git diff-tree --no-commit-id -r --name-only HEAD | wc -l)
printf "\n✓ Committed on %s\n" "$BRANCH"
printf " %s %s\n" "$HASH" "$SUBJECT"
printf " %d file(s) changed\n\n" "$FILES"
Enhancement 3 — Check for Secrets in pre-commit¶
Block commits that contain API keys, passwords, or tokens:
check_secrets() {
local patterns=(
'password\s*=\s*["\x27][^\x27"]{6,}'
'api[_-]?key\s*=\s*["\x27][^\x27"]{16,}'
'secret\s*=\s*["\x27][^\x27"]{6,}'
'AKIA[0-9A-Z]{16}' # AWS access key
'sk-[a-zA-Z0-9]{32,}' # OpenAI key pattern
'ghp_[a-zA-Z0-9]{36}' # GitHub PAT
)
local found=false
for pattern in "${patterns[@]}"; do
local matches
matches=$(git diff --cached | grep -iE "$pattern" || true)
if [[ -n "$matches" ]]; then
echo "[pre-commit] Possible secret detected (pattern: $pattern):" >&2
echo "$matches" | head -3 >&2
found=true
fi
done
[[ "$found" == true ]] && return 1
return 0
}
False positives are common
Secret scanning generates false positives on test fixtures, documentation, and example configs. Add a # noqa-secret comment convention for intentional exceptions, and have the hook skip lines containing that marker.
Enhancement 4 — Branch Naming Convention¶
Enforce branch names like feat/, fix/, chore/ in a pre-push check:
check_branch_name() {
local branch
branch=$(git symbolic-ref --short HEAD)
local pattern='^(feat|fix|docs|chore|refactor|test|ci|release)/.+'
if [[ "$branch" == "main" || "$branch" == "develop" ]]; then
return 0 # protected branches are exempt
fi
if ! echo "$branch" | grep -qE "$pattern"; then
echo "[pre-push] Branch '$branch' does not follow naming convention." >&2
echo "[pre-push] Expected: <type>/<description> e.g. feat/user-auth" >&2
return 1
fi
}
Enhancement 5 — Run Tests Before Push¶
Run your test suite before pushing — catch failures before CI does:
# Add to pre-push:
run_tests() {
local test_cmd=""
# Auto-detect test framework
if [[ -f "package.json" ]]; then
test_cmd="npm test"
elif [[ -f "Makefile" ]] && grep -q "^test:" Makefile; then
test_cmd="make test"
elif [[ -f "pytest.ini" || -f "setup.py" ]]; then
test_cmd="python -m pytest"
fi
[[ -z "$test_cmd" ]] && return 0
echo "[pre-push] Running: $test_cmd"
if $test_cmd; then
echo "[pre-push] Tests passed"
else
echo "[pre-push] Tests failed — push aborted" >&2
echo "[pre-push] Use --no-verify to skip (not recommended)" >&2
return 1
fi
}
Enhancement 6 — Hook Manager with Enable/Disable¶
Allow individual hooks to be toggled without deleting them:
# In install.sh — add enable/disable commands:
case "${1:-install}" in
install)
for hook in "${HOOKS[@]}"; do
ln -sf "${SCRIPT_DIR}/${hook}" "${HOOKS_DIR}/${hook}"
done
;;
disable)
hook="${2:?disable requires a hook name}"
mv "${HOOKS_DIR}/${hook}" "${HOOKS_DIR}/${hook}.disabled"
echo "Disabled: $hook"
;;
enable)
hook="${2:?enable requires a hook name}"
mv "${HOOKS_DIR}/${hook}.disabled" "${HOOKS_DIR}/${hook}"
echo "Enabled: $hook"
;;
status)
for hook in "${HOOKS[@]}"; do
if [-L "${HOOKS_DIR}/${hook}"](<../../-L "${HOOKS_DIR}/${hook}".md>); then
echo " [ON] $hook"
elif [-f "${HOOKS_DIR}/${hook}.disabled"](<../../-f "${HOOKS_DIR}/${hook}.disabled">); then
echo " [OFF] $hook"
else
echo " [--] $hook (not installed)"
fi
done
;;
esac