#!/bin/bash # Get the commit message file path from the first argument commit_msg_file="$1" # Read the commit message commit_msg=$(cat "$commit_msg_file") # Colors for output red='\033[0;31m' yellow='\033[1;33m' no_color='\033[0m' # Get the first line (subject) subject=$(echo "$commit_msg" | head -n1) # Get the second line second_line=$(echo "$commit_msg" | sed -n '2p') # Get the third line third_line=$(echo "$commit_msg" | sed -n '3p') # Get the rest of the message (body) body=$(echo "$commit_msg" | tail -n +4) # Check subject length (max 80 characters) if [ ${#subject} -gt 80 ]; then echo -e "${yellow}Warning: Commit message subject is too long (max 80 characters)${no_color}" echo -e "Current length: ${#subject} characters" fi # Check if second line is blank if [ ! -z "$second_line" ]; then echo -e "${yellow}Warning: Second line should be blank${no_color}" fi # Check third line format if [ ! -z "$third_line" ]; then if [[ "$third_line" =~ ^(refs|ref:) ]]; then echo -e "${red}Error: Third line should not start with 'refs' or 'ref:'${no_color}" >&2 echo -e "Use 'ref ', 'fixes ', or 'closes ' instead" >&2 echo -e "${yellow}Press Enter to edit the message...${no_color}" >&2 read < /dev/tty # Wait for Enter key press from the terminal # Get the configured Git editor editor=$(git var GIT_EDITOR) if [ -z "$editor" ]; then editor=${VISUAL:-${EDITOR:-vi}} # Fallback logic similar to Git fi # Re-open the editor on the commit message file, connected to the terminal $editor "$commit_msg_file" < /dev/tty # Re-read the potentially modified commit message after editing commit_msg=$(cat "$commit_msg_file") # Need to update related variables as well subject=$(echo "$commit_msg" | head -n1) second_line=$(echo "$commit_msg" | sed -n '2p') third_line=$(echo "$commit_msg" | sed -n '3p') body=$(echo "$commit_msg" | tail -n +4) # Re-check the third line *again* after editing if [[ "$third_line" =~ ^(refs|ref:) ]]; then echo -e "${red}Error: Third line still starts with 'refs' or 'ref:'. Commit aborted.${no_color}" >&2 exit 1 # Abort commit if still invalid fi # If fixed, the script will continue to the next checks fi if ! [[ "$third_line" =~ ^(ref|fixes|closes)\ .*$ ]]; then echo -e "${yellow}Warning: Third line should start with 'ref', 'fixes', or 'closes' followed by an issue link${no_color}" >&2 fi fi # Check for body content (why explanation) if [ -z "$body" ]; then echo -e "${yellow}Warning: Missing explanation of why this change was made${no_color}" echo -e "The body should explain: why this, why now, why not something else?" fi # Check for emoji in user-facing changes if [[ "$subject" =~ ^[^[:space:]]*[[:space:]] ]]; then first_word="${subject%% *}" if [[ ! "$first_word" =~ ^[[:punct:]] ]]; then echo -e "${yellow}Warning: User-facing changes should start with an emoji${no_color}" echo -e "Common emojis: ✨ (Feature), 🎨 (Improvement), 🐛 (Bug Fix), 🌐 (i18n), 💡 (User-facing)" fi fi # Check for past tense verbs in subject past_tense_words="Fixed|Changed|Updated|Improved|Added|Removed|Reverted|Moved|Released|Bumped|Cleaned" if ! echo "$subject" | grep -iE "$past_tense_words" > /dev/null; then echo -e "${yellow}Warning: Subject line should use past tense${no_color}" echo -e "Use one of: Fixed, Changed, Updated, Improved, Added, Removed, Reverted, Moved, Released, Bumped, Cleaned" fi exit 0