Skip to content

Instantly share code, notes, and snippets.

@whomwah
Last active October 10, 2025 15:10
Show Gist options
  • Save whomwah/25b868ac1cbca6dc22bea721b74f49ee to your computer and use it in GitHub Desktop.
Save whomwah/25b868ac1cbca6dc22bea721b74f49ee to your computer and use it in GitHub Desktop.
A bash script that creates clean, markdown-formatted summaries of commits between main and your current branch - perfect for pull request descriptions and release notes.

Git Branch Summary Generator

A bash script that creates clean, markdown-formatted summaries of commits between main and your current branch - perfect for pull request descriptions and release notes.

Setup & Usage

  1. Save as summary-git in your ~/bin or another directory in your $PATH
  2. Make executable: chmod +x summary-git
  3. Run from any git repository: summary-git

Features

  • Smart commit processing: Strips semantic commit prefixes (feat:, fix:, etc.) and capitalizes messages
  • Intelligent list handling: Processes both markdown lists and inline - separated items
  • Clean formatting: Word-wraps at 76 characters with proper indentation
  • Ready-to-use output: Generates markdown that's perfect for GitHub PR descriptions

Example Output

## Summary based on commit messages

- Implement JWT authentication
  - Add login endpoint
  - Add token validation middleware
  - Update user model with tokens
- Resolve API timeout issues
  Updated connection pooling and added retry logic
#!/bin/bash
echo "## Summary based on commit messages"
echo ""
# Function to process and output list items
process_list_content() {
local content="$1"
# Collapse all whitespace and newlines into single spaces first
content=$(echo "$content" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
# Check if content has inline list separators (space-dash-space)
if [[ "$content" =~ [[:space:]]-[[:space:]] ]]; then
# Split on " - " and process each item as a separate list item
echo "$content" | sed 's/ - /\n- /g' | while IFS= read -r item; do
if [[ -n "$item" && "$item" != " " ]]; then
item=$(echo "$item" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ -n "$item" ]]; then
# Add leading dash if it doesn't start with one
if [[ ! "$item" =~ ^- ]]; then
item="- $item"
fi
echo " $item" | fold -s -w 76 | sed 's/^/ /'
fi
fi
done
else
# Process line by line for regular list items
echo "$content" | while IFS= read -r line; do
if [[ -n "$line" && "$line" != " " ]]; then
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ -n "$line" ]]; then
# Check if this line starts with list markers
if [[ "$line" =~ ^[[:space:]]*[*-][[:space:]] ]]; then
echo " $line" | fold -s -w 76 | sed 's/^/ /'
else
# Regular text line
echo " $line" | fold -s -w 76 | sed 's/^/ /'
fi
fi
fi
done
fi
}
# Get the git log and process it
git log --pretty=format:"COMMIT_START%s%nBODY_START%b%nCOMMIT_END" --reverse main..HEAD | \
while IFS= read -r line; do
if [[ $line == COMMIT_START* ]]; then
# Extract commit message and remove semantic commit prefixes
message="${line#COMMIT_START}"
# Remove common semantic commit prefixes (case insensitive)
message=$(echo "$message" | sed -E 's/^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\([^)]*\))?: ?//i')
# Capitalize first letter
message="$(echo ${message:0:1} | tr '[:lower:]' '[:upper:]')${message:1}"
echo "- $message"
in_body=false
body_content=""
elif [[ $line == BODY_START* ]]; then
body="${line#BODY_START}"
body_content="$body"
in_body=true
elif [[ $line == COMMIT_END ]]; then
# Process accumulated body content
if [[ -n "$body_content" && "$body_content" != " " ]]; then
# Check if it contains list items (either format)
if [[ "$body_content" =~ [*-][[:space:]] ]] || [[ "$body_content" =~ [[:space:]]-[[:space:]] ]]; then
process_list_content "$body_content"
else
body_content=$(echo "$body_content" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ -n "$body_content" ]]; then
echo " $body_content" | fold -s -w 76 | sed 's/^/ /'
fi
fi
fi
in_body=false
body_content=""
elif [[ $in_body == true && -n "$line" && "$line" != " " ]]; then
# Accumulate body content
if [[ -n "$body_content" ]]; then
body_content="$body_content $line"
else
body_content="$line"
fi
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment