Chapter 8.6 — prepare-commit-msg — The Assistant Hook☕ 13 min read

prepare-commit-msg Hook

Auto-populate karo, developer ko bas WHY likhna hai. Ticket, template, Co-authored-by — sab automatic.

01What is prepare-commit-msg

prepare-commit-msg is the hook that runs BEFORE your commit message editor opens. Think of it as a pre-fill assistant — it writes to the message file before you see it.

It receives 3 arguments:

  • $1 — path to the message file (this is what you write to)
  • $2 — message source: "message" (-m flag), "template" (-t flag), "merge", "squash", or "commit" (amend)
  • $3 — commit SHA (only for amend/squash operations)

The message source ($2) is critical — it tells you WHERE the message came from so you can decide whether to modify it.

Possible values of $2:

  • empty string — user ran git commit (editor mode), no existing message
  • "message" — user used git commit -m "..."
  • "template" — user used git commit -t template_file
  • "merge" — this is a merge commit (auto-generated message)
  • "squash" — this is a squash merge (combined messages)
  • "commit" — user is amending a commit (git commit --amend)

Unlike commit-msg (which VALIDATES after the user writes), prepare-commit-msg PRE-POPULATES before the user writes. The developer sees a pre-filled message in their editor and just adds their description.

This hook should rarely block commits (exit 1). It is for automation, not enforcement.

# Understand the arguments
cat > .git/hooks/prepare-commit-msg << 'EOF'
#!/bin/bash
MSG_FILE=$1      # Path to message file
MSG_SOURCE=$2    # Where the message came from
COMMIT_SHA=$3    # SHA (only for amend/squash)

echo "Message file: $MSG_FILE"
echo "Source: $MSG_SOURCE"
echo "Commit SHA: $COMMIT_SHA"

# Don't modify anything yet — just observe
EOF

chmod +x .git/hooks/prepare-commit-msg

# Try different commit types:
git commit -m "test"           # source = "message"
git commit                     # source = "" (editor)
git commit --amend             # source = "commit"
# During merge: source = "merge"
02Hook Lifecycle

The #1 use case for prepare-commit-msg: extract the ticket number from the branch name and add it to the message automatically.

Branch: feature/JIRA-456-add-auth → Message starts with [JIRA-456]

The pattern is simple: git rev-parse --abbrev-ref HEAD gets the branch name, then extract the ticket with a regex like [A-Z]+-[0-9]+.

Important: only add the ticket if it is not already in the message — always check before appending to avoid duplication.

This saves developers from manually typing ticket numbers on every single commit. No more "forgot to add the JIRA ticket" excuses.

For GitHub-style branches: extract #123 from fix-123-bug and add (#123) to the message.

# Auto-add JIRA ticket from branch name
cat > .git/hooks/prepare-commit-msg << 'EOF'
#!/bin/bash
MSG_FILE=$1
MSG_SOURCE=$2

# Don't modify merge, squash, or amend messages
if [ "$MSG_SOURCE" = "merge" ] || [ "$MSG_SOURCE" = "squash" ] || [ "$MSG_SOURCE" = "commit" ]; then
  exit 0
fi

# Get current branch name
BRANCH=$(git rev-parse --abbrev-ref HEAD)

# Extract ticket number (JIRA-123, PROJ-456, etc.)
TICKET=$(echo $BRANCH | grep -oE '[A-Z]+-[0-9]+')

if [ -n "$TICKET" ]; then
  # Check if ticket is already in the message
  EXISTING=$(cat "$MSG_FILE")
  if ! echo "$EXISTING" | grep -q "$TICKET"; then
    # Prepend ticket to message
    echo "[$TICKET] $EXISTING" > "$MSG_FILE"
  fi
fi

exit 0
EOF

chmod +x .git/hooks/prepare-commit-msg

# Now when you commit on branch feature/JIRA-456-add-auth:
git commit
# Editor opens with: [JIRA-456] 
# Developer just types the description after the ticket!
03Practical Use Cases

prepare-commit-msg can inject a template that guides developers on what to write. Instead of facing a blank editor, they see a structured form with helpful reminders.

A good template includes:

  • First line — subject (what changed, max 72 chars)
  • Blank line — separator between subject and body
  • Body — describe WHY the change was made (the diff shows WHAT)
  • Footer — references, breaking changes, co-authors

You can include reminders as comments (# lines are ignored in commit messages). This ensures consistent message structure across the team.

Templates are especially helpful for new developers who don't know the team's commit message conventions yet.

# Inject a template via prepare-commit-msg
cat > .git/hooks/prepare-commit-msg << 'EOF'
#!/bin/bash
MSG_FILE=$1
MSG_SOURCE=$2

# Don't modify merge/squash/amend
if [ "$MSG_SOURCE" = "merge" ] || [ "$MSG_SOURCE" = "squash" ] || [ "$MSG_SOURCE" = "commit" ]; then
  exit 0
fi

# Write template to message file
cat > "$MSG_FILE" << TEMPLATE
# Type your commit subject here (max 72 chars)
# 
# Describe WHY this change was made (not what — diff shows what)
# 
# Footer: References, Breaking Changes, etc.
TEMPLATE

exit 0
EOF

chmod +x .git/hooks/prepare-commit-msg

# Now git commit opens editor with:
# # Type your commit subject here (max 72 chars)
# # 
# # Describe WHY this change was made
# # 
# # Footer: References, Breaking Changes, etc.
#
# Developer sees instructions, # lines are stripped on save!
💡 Pro Tip: Lines starting with # in the commit message file are treated as comments and are automatically stripped by Git when the commit is created. This means you can add helpful instructions as comments in the template — developers see them in the editor but they don't appear in the final commit message.
04Writing the Script

In pair programming, both authors should be credited in the commit. The Co-authored-by: trailer in the commit footer gives both authors credit on GitHub.

prepare-commit-msg can auto-add this for teams that always pair program. It checks a pairing configuration file (like .pair) and adds the current pair's information.

GitHub recognizes Co-authored-by: — both authors get contribution credit on their profile. This is the standard way to credit pair programming in Git.

The format must be exact: Co-authored-by: Name <email> — GitHub parses this specific format.

# Auto-add Co-authored-by
cat > .git/hooks/prepare-commit-msg << 'EOF'
#!/bin/bash
MSG_FILE=$1
MSG_SOURCE=$2

# Don't modify merge/squash/amend
if [ "$MSG_SOURCE" = "merge" ] || [ "$MSG_SOURCE" = "squash" ]; then
  exit 0
fi

# Check if .pair file exists (team pairing config)
if [ -f ".pair" ]; then
  PAIR=$(cat .pair)
  # .pair contains: "Jane Smith "
  
  EXISTING=$(cat "$MSG_FILE")
  
  # Only add if not already present
  if ! echo "$EXISTING" | grep -q "Co-authored-by"; then
    echo "" >> "$MSG_FILE"
    echo "Co-authored-by: $PAIR" >> "$MSG_FILE"
  fi
fi

exit 0
EOF

chmod +x .git/hooks/prepare-commit-msg

# Create .pair file
echo "Priya Sharma " > .pair

# Now commits automatically include:
# feat: add login
#
# Co-authored-by: Priya Sharma 

# Both authors get credit on GitHub!
05Best Practices

DON'T modify merge commit messages — they contain important branch information like "Merge branch 'feature' into main". Overwriting this breaks Git's automatic merge tracking.

DON'T modify squash commit messages — they're auto-generated from multiple commits and contain the full history of the squashed branch.

DON'T modify amend messages — the developer intentionally changed the message. Your hook would re-add things they just removed.

DON'T overwrite the entire message — always prepend or append. Overwriting destroys existing content including -m messages.

DON'T add metadata that's already in the message — always check before adding to avoid duplicates.

Use $2 (message source) to decide whether to modify: only modify when source is empty or "message".

The prepare-commit-msg hook is for CONVENIENCE, not ENFORCEMENT. If you need to enforce message format, use the commit-msg hook instead. prepare-commit-msg should auto-populate helpful information; commit-msg should validate the final result. Don't try to do both in one hook.

Lo kar liya — Key Points:

  • ✅ prepare-commit-msg runs BEFORE the editor opens — it auto-populates the message
  • ✅ It receives 3 arguments: $1 = message file, $2 = message source, $3 = commit SHA
  • ✅ Primary use: extract ticket number from branch name and prepend to message
  • ✅ Don't modify merge, squash, or amend messages — check $2 before modifying
  • ✅ Use comment lines (#) in templates for instructions — Git strips them from final message
  • ✅ Auto-add Co-authored-by for pair programming — both authors get credit on GitHub
  • ✅ This hook is for CONVENIENCE (auto-fill), not ENFORCEMENT (use commit-msg for that)
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase