#!/bin/sh # Rejects a commit message that breaks the rules in AGENTS.md: a subject of 50 # characters or fewer without a final period, one blank line, a body, body lines # of 72 characters or fewer, and real line breaks instead of "\n". Prose # paragraphs fill each line before wrapping. Formatted blocks keep their line # breaks. A body line without spaces, such as a URL, may be longer. set -eu file=$1 subject=$(sed -n 1p "$file") case $subject in "Merge "* | "Revert "* | "fixup! "* | "squash! "*) exit 0 ;; esac fail() { printf 'commit-msg: %s\n' "$1" "write the message to a file and commit with git commit -F." >&2 exit 1 } if grep -q '\\n' "$file"; then fail 'the message has a literal "\n"; use real line breaks' fi [ ${#subject} -le 50 ] || fail "the subject has ${#subject} characters; the limit is 50" case $subject in *.) fail "the subject ends with a period" ;; esac [ -z "$(sed -n 2p "$file")" ] || fail "the second line must be blank" sed -n '3,$p' "$file" | grep -q '[^[:space:]]' || fail "the message has no body" long=$(sed -n '3,$p' "$file" | awk 'length($0) > 72 && $0 ~ / / { print NR + 2; exit }') [ -z "$long" ] || fail "line $long is longer than 72 characters" short=$(awk ' function check_paragraph( i, word) { if (!formatted && !bad_line) { for (i = 1; i < count; i++) { word = lines[i + 1] sub(/[[:space:]].*$/, "", word) if (length(lines[i]) + 1 + length(word) <= 72) { bad_line = numbers[i] break } } } count = 0 formatted = 0 } NR <= 2 { next } fence != "" { if ($0 ~ /^(`{3,}|~{3,})[[:space:]]*$/ && substr($0, 1, 1) == fence) { match($0, /^(`+|~+)/) if (RLENGTH >= fence_length) fence = "" } next } /^(`{3,}|~{3,})/ { check_paragraph() match($0, /^(`+|~+)/) fence = substr($0, 1, 1) fence_length = RLENGTH next } /^[[:space:]]*$/ { check_paragraph() next } { if ($0 ~ /^[[:space:]>#|]/ || $0 ~ /^([-*+][[:space:]]|[0-9]+[.)][[:space:]])/ || $0 ~ /^[-=*_]{3,}$/ || $0 ~ /^[[:alnum:]][[:alnum:]-]*:[[:space:]]/) { formatted = 1 } lines[++count] = $0 numbers[count] = NR } END { check_paragraph() if (bad_line) print bad_line } ' "$file") [ -z "$short" ] || fail "unnecessary line break after line $short; reflow the paragraph to 72 characters"