Files
2025-10-24 14:32:45 +08:00

55 lines
1.5 KiB
Bash
Executable File

#!/bin/sh
# commit-msg hook to enforce Conventional Commits (https://www.conventionalcommits.org/)
# This script checks the commit message subject (first line) for a conventional commit format.
# If the message does not conform, the hook exits non-zero to block the commit.
# Read the commit message (first line)
if [ -z "$1" ]; then
echo "commit-msg hook: no message file provided" >&2
exit 0
fi
MSG_FILE="$1"
read -r FIRST_LINE < "$MSG_FILE" || FIRST_LINE=""
# Trim leading/trailing whitespace
FIRST_LINE="$(echo "$FIRST_LINE" | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//')"
# Allow empty message (let git handle it), or allow merges/reverts
case "$FIRST_LINE" in
Merge:*|merge:*|Revert:*|revert:*)
exit 0
;;
esac
# Conventional Commit regex (POSIX ERE)
# [type](scope)!?: subject
# types: feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|wip
# scope: any chars except )
regex='^\[(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|wip)\](\([^\)]+\))?(!)?: .+'
printf "%s" "$FIRST_LINE" | grep -E "$regex" >/dev/null 2>&1
if [ $? -eq 0 ]; then
exit 0
fi
cat <<'EOF' >&2
ERROR: Commit message does not follow Conventional Commits.
Expected format:
[type](scope)?: subject
Examples:
[feat]: add new feature
[fix(parser)]: handle edge case
[docs]!: update API docs (breaking change)
Allowed types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, wip
You can bypass this hook locally by running:
git commit --no-verify
EOF
exit 1