Skip to content

Instantly share code, notes, and snippets.

@withakay
Last active June 7, 2025 15:56
Show Gist options
  • Save withakay/9a4b174f8a5a28b8abba3e2ddf23db88 to your computer and use it in GitHub Desktop.
Save withakay/9a4b174f8a5a28b8abba3e2ddf23db88 to your computer and use it in GitHub Desktop.
Use Claude Code to improve your last git commit message

Git Commit Message Improver

A powerful bash script that uses Claude CLI to automatically improve generic or poorly written git commit messages. It analyses your code changes and suggests more descriptive, conventional commit messages.

Features

  • 🤖 AI-Powered: Uses Claude to analyse your changes and generate meaningful commit messages
  • 📝 Smart Detection: Automatically identifies generic commit messages like "update", "fix", "changes"
  • 🔄 Batch Processing: Can improve all unpushed commits on your current branch
  • Model Selection: Choose between different Claude models for speed vs quality
  • 🎨 Coloured Output: Clear, colourful terminal output for better readability
  • Interactive: Confirms each change before applying
  • 🔧 Git Integration: Easy installation as git aliases

Prerequisites

  • Git
  • Claude CLI installed and authenticated
  • Bash shell

Installation

  1. Download the script:

    curl -O https://gist.github.com/withakay/9a4b174f8a5a28b8abba3e2ddf23db88#file-git-improve-commit-sh
    chmod +x git-improve-commit.sh
  2. Install git aliases (recommended):

    ./git-improve-commit.sh --install

    This creates the following git aliases:

    • git ic - Improve the last commit
    • git ib - Improve all unpushed commits on current branch
    • git improve-commit - Long form of ic
    • git improve-branch - Long form of ib

Usage

Basic Usage

# Improve the last commit (default action)
./git-improve-commit.sh

# Or using git alias after installation
git ic

Improve Multiple Commits

# Improve all unpushed commits on current branch
./git-improve-commit.sh --branch

# Or using git alias
git ib

Model Selection

Use faster models for quicker responses:

# Use Haiku (fastest model)
./git-improve-commit.sh --model claude-3-haiku-20240307

# Or with alias
git ic -m claude-3-haiku-20240307

Set Default Model

# Set a default model in git config
git config --global commit.claude-model claude-3-haiku-20240307

# Now all commands will use Haiku by default
git ic

Available Models

  • claude-3-haiku-20240307 - Fastest, good for simple commits
  • claude-3-sonnet-20240229 - Balanced speed and quality
  • claude-3-opus-20240229 - Highest quality, slower

Configuration

Environment Variables

  • DEBUG=1 - Show detailed debug information
  • VERBOSE=1 - Show error details
  • CLAUDE_MODEL=model-name - Set default model

Example:

DEBUG=1 ./git-improve-commit.sh

Git Config

Store your preferred model permanently:

git config --global commit.claude-model claude-3-haiku-20240307

How It Works

  1. Analyses Changes: Extracts the git diff for your commit
  2. Detects Generic Messages: Identifies commits with generic messages like "update", "fix", etc.
  3. Generates Improvement: Sends the diff and current message to Claude for analysis
  4. Suggests Better Message: Claude suggests a conventional commit message
  5. Confirms Change: You review and approve the new message
  6. Updates Commit: Applies the new message using git commit --amend or interactive rebase

Generic Message Detection

The script automatically detects these patterns as generic:

  • Single words: update, fix, changes, updates, fixes, wip, commit, save, done, test, testing, stuff
  • Patterns: minor*, small*, quick*, add*

Troubleshooting

Test Claude CLI Connection

./git-improve-commit.sh --test

Debug Mode

DEBUG=1 ./git-improve-commit.sh

Common Issues

  1. "claude command not found"

  2. "No upstream branch found"

    • Set an upstream branch: git push --set-upstream origin branch-name
  3. Authentication errors

    • Ensure Claude CLI is properly authenticated
    • Check your API key configuration

Examples

Before and After

Before: add
After: feat: implement user authentication middleware

Before: fix
After: fix: resolve null pointer exception in payment processor

Before: update
After: docs: update API documentation with new endpoints

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - feel free to use this in your projects!

Acknowledgments

  • Powered by Claude from Anthropic
  • Inspired by the need for better commit messages in development teams
#!/bin/bash
# Git commit message improvement script using Claude CLI
# Can improve the last commit or all unpushed commits on current branch
set -e
# Colour codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Colour
# Default model (empty means use Claude Code's default)
DEFAULT_MODEL=""
# Function to print coloured output
print_colour() {
local colour=$1
shift
echo -e "${colour}$@${NC}"
}
# Function to check if we're in a git repository
check_git_repo() {
if ! git rev-parse --git-dir > /dev/null 2>&1; then
print_colour $RED "Error: Not in a git repository"
exit 1
fi
}
# Function to check if message is generic
is_generic_message() {
local msg="$1"
local msg_lower=$(echo "$msg" | tr '[:upper:]' '[:lower:]' | xargs)
local generic_patterns=(
"^update$"
"^fix$"
"^changes$"
"^updates$"
"^fixes$"
"^wip$"
"^commit$"
"^save$"
"^done$"
"^test$"
"^testing$"
"^stuff$"
"^minor.*$"
"^small.*$"
"^quick.*$"
"^add.*$"
)
for pattern in "${generic_patterns[@]}"; do
if [[ "$msg_lower" =~ $pattern ]]; then
return 0
fi
done
return 1
}
# Function to get improved commit message from Claude
get_improved_message() {
local original_msg="$1"
local commit_sha="$2"
# Get the diff for this commit
local diff=""
if [ -z "$commit_sha" ]; then
# For staged changes
diff=$(git diff --cached)
else
# For existing commit
diff=$(git show --format="" "$commit_sha")
fi
# Check if diff is empty
if [ -z "$diff" ]; then
print_colour $YELLOW "Warning: No changes found in commit" >&2
return 1
fi
# Create a temporary file with the context
local temp_context=$(mktemp)
cat > "$temp_context" << EOF
The current commit message is: "$original_msg"
Here are the changes:
$diff
Please analyze these changes and provide a better, more descriptive commit message that:
1. Summarizes what was changed
2. Explains why (if apparent from the changes)
3. Follows conventional commit format if possible (feat:, fix:, docs:, etc.)
4. Is concise but informative (ideally under 72 characters for the first line)
Just output the new commit message, nothing else.
EOF
# Build claude command with optional model
local claude_cmd="claude -p"
if [ -n "$CLAUDE_MODEL" ]; then
claude_cmd="$claude_cmd --model $CLAUDE_MODEL"
fi
# Debug mode - show command if DEBUG env var is set
if [ -n "$DEBUG" ]; then
print_colour $YELLOW "Debug: Running command: $claude_cmd" >&2
print_colour $YELLOW "Debug: Context length: $(wc -c < "$temp_context") bytes" >&2
print_colour $YELLOW "Debug: First 100 chars of diff: ${diff:0:100}..." >&2
fi
# Call Claude CLI to improve the message, capture both stdout and stderr
local error_file=$(mktemp)
local output_file=$(mktemp)
# Run the command and capture everything
# Using proper Claude CLI syntax
$claude_cmd < "$temp_context" >"$output_file" 2>"$error_file"
local exit_code=$?
# Read the output
local new_msg=$(cat "$output_file")
local error_msg=$(cat "$error_file")
# Debug output
if [ -n "$DEBUG" ]; then
print_colour $YELLOW "Debug: Exit code: $exit_code" >&2
print_colour $YELLOW "Debug: Output length: $(echo -n "$new_msg" | wc -c) chars" >&2
print_colour $YELLOW "Debug: Error output: $error_msg" >&2
if [ -n "$new_msg" ]; then
print_colour $YELLOW "Debug: Raw output: '$new_msg'" >&2
fi
fi
# Check for errors
if [ $exit_code -ne 0 ]; then
if [ -n "$DEBUG" ] || [ -n "$VERBOSE" ]; then
print_colour $RED "Error: Claude CLI failed with exit code $exit_code" >&2
if [ -n "$error_msg" ]; then
print_colour $RED "Error message: $error_msg" >&2
fi
fi
# Check if claude is installed
if ! command -v claude &> /dev/null; then
print_colour $RED "Error: 'claude' command not found. Please install Claude CLI first." >&2
print_colour $YELLOW "Visit: https://github.com/anthropics/claude-cli" >&2
fi
fi
# Clean up temp files
rm -f "$temp_context" "$error_file" "$output_file"
if [ $exit_code -eq 0 ] && [ -n "$new_msg" ]; then
# Remove any markdown formatting that might be present
new_msg=$(echo "$new_msg" | sed 's/^```.*//g' | sed 's/```$//g' | xargs)
echo "$new_msg"
return 0
else
return 1
fi
}
# Function to confirm action with user
confirm() {
local prompt="$1"
local response
while true; do
read -p "$prompt (y/n): " response
case $response in
[Yy]* ) return 0;;
[Nn]* ) return 1;;
* ) echo "Please answer yes (y) or no (n).";;
esac
done
}
# Function to improve last commit
improve_last_commit() {
local commit_sha=$(git rev-parse HEAD)
local original_msg=$(git log -1 --pretty=%B)
print_colour $YELLOW "Current commit message: '$original_msg'"
if [ -n "$CLAUDE_MODEL" ]; then
print_colour $YELLOW "Using model: $CLAUDE_MODEL"
fi
if ! is_generic_message "$original_msg"; then
print_colour $GREEN "Commit message appears to be descriptive already."
if ! confirm "Do you want to improve it anyway?"; then
return 0
fi
fi
print_colour $YELLOW "Using Claude CLI to generate a better commit message..."
local new_msg=$(get_improved_message "$original_msg" "$commit_sha")
if [ $? -eq 0 ] && [ -n "$new_msg" ] && [ "$new_msg" != "$original_msg" ]; then
print_colour $GREEN "Suggested commit message: '$new_msg'"
if confirm "Apply this commit message?"; then
git commit --amend -m "$new_msg"
print_colour $GREEN "✓ Commit message updated successfully!"
else
print_colour $YELLOW "Commit message not changed."
fi
else
print_colour $RED "Failed to generate improved message, keeping original"
fi
}
# Function to improve all unpushed commits on current branch
improve_branch_commits() {
local upstream=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null || echo "")
if [ -z "$upstream" ]; then
print_colour $RED "No upstream branch found. Please set an upstream branch first."
exit 1
fi
# Get list of unpushed commits
local unpushed_commits=$(git rev-list $upstream..HEAD)
if [ -z "$unpushed_commits" ]; then
print_colour $YELLOW "No unpushed commits found on current branch."
return 0
fi
local commit_count=$(echo "$unpushed_commits" | wc -l)
print_colour $YELLOW "Found $commit_count unpushed commit(s) on current branch."
if [ -n "$CLAUDE_MODEL" ]; then
print_colour $YELLOW "Using model: $CLAUDE_MODEL"
fi
# Process commits from oldest to newest
local commits_array=()
while IFS= read -r commit; do
commits_array+=("$commit")
done <<< "$(echo "$unpushed_commits" | tac)"
local improved_count=0
for commit_sha in "${commits_array[@]}"; do
local original_msg=$(git log -1 --pretty=%B "$commit_sha")
print_colour $YELLOW "\nCommit: $commit_sha"
print_colour $YELLOW "Current message: '$original_msg'"
local should_improve=false
if is_generic_message "$original_msg"; then
print_colour $YELLOW "This appears to be a generic commit message."
should_improve=true
else
if confirm "Do you want to improve this message?"; then
should_improve=true
fi
fi
if [ "$should_improve" = true ]; then
print_colour $YELLOW "Generating improved message..."
local new_msg=$(get_improved_message "$original_msg" "$commit_sha")
if [ $? -eq 0 ] && [ -n "$new_msg" ] && [ "$new_msg" != "$original_msg" ]; then
print_colour $GREEN "Suggested message: '$new_msg'"
if confirm "Apply this commit message?"; then
# Use interactive rebase to change the commit message
GIT_SEQUENCE_EDITOR="sed -i '1s/pick/reword/'" git rebase -i $commit_sha^
GIT_EDITOR="echo '$new_msg' >" git rebase --continue
((improved_count++))
print_colour $GREEN "✓ Commit message updated!"
else
print_colour $YELLOW "Skipping this commit."
fi
else
print_colour $RED "Failed to generate improved message for this commit."
fi
fi
done
print_colour $GREEN "\nSummary: Improved $improved_count out of $commit_count unpushed commits."
}
# Function to install as git alias
install_git_alias() {
local script_path=$(realpath "$0")
print_colour $YELLOW "Installing git aliases..."
# Long form aliases
git config --global alias.improve-commit "!$script_path"
git config --global alias.improve-branch "!$script_path --branch"
# Short form aliases
git config --global alias.ic "!$script_path"
git config --global alias.ib "!$script_path --branch"
print_colour $GREEN "✓ Git aliases installed successfully!"
print_colour $GREEN " Long form:"
print_colour $GREEN " - Use 'git improve-commit' to improve the last commit"
print_colour $GREEN " - Use 'git improve-branch' to improve all unpushed commits on current branch"
print_colour $GREEN " Short form:"
print_colour $GREEN " - Use 'git ic' to improve the last commit"
print_colour $GREEN " - Use 'git ib' to improve all unpushed commits on current branch"
}
# Main script logic
main() {
# Check for model environment variable or flag
CLAUDE_MODEL="$DEFAULT_MODEL"
# Process model flag if present
while [[ $# -gt 0 ]]; do
case $1 in
--model|-m)
CLAUDE_MODEL="$2"
shift 2
;;
*)
break
;;
esac
done
check_git_repo
# Parse command line arguments
case "${1:-}" in
--last|-l)
improve_last_commit
;;
--branch|-b)
improve_branch_commits
;;
--install)
install_git_alias
;;
--test)
# Test claude CLI functionality
print_colour $YELLOW "Testing Claude CLI installation..."
if ! command -v claude &> /dev/null; then
print_colour $RED "✗ claude command not found in PATH"
exit 1
fi
print_colour $GREEN "✓ claude found at: $(which claude)"
# Try a simple test
print_colour $YELLOW "Testing claude with a simple prompt..."
local test_output=$(echo "Say 'Hello' and nothing else" | claude 2>&1)
local test_exit=$?
if [ $test_exit -eq 0 ]; then
print_colour $GREEN "✓ claude is working! Output: $test_output"
else
print_colour $RED "✗ claude test failed with exit code: $test_exit"
print_colour $RED "Error output: $test_output"
print_colour $YELLOW "\nPossible issues:"
print_colour $YELLOW "1. Claude CLI may not be authenticated"
print_colour $YELLOW "2. Network connection issues"
print_colour $YELLOW "3. Invalid API configuration"
fi
;;
--help|-h)
cat << EOF
Git Commit Message Improvement Script
Usage: $0 [OPTIONS]
Options:
--model, -m MODEL Use specific Claude model (e.g., claude-3-haiku-20240307)
--last, -l Improve the last commit message (default)
--branch, -b Improve all unpushed commits on current branch
--install Install as git aliases (improve-commit, improve-branch, ic, ib)
--help, -h Show this help message
Environment Variables:
DEBUG=1 Show debug information
VERBOSE=1 Show error details
CLAUDE_MODEL=... Set default model
Model Options:
You can specify a model in three ways:
1. Command line: $0 --model claude-3-haiku-20240307
2. Environment variable: CLAUDE_MODEL=claude-3-haiku-20240307 $0
3. Git config: git config --global commit.claude-model claude-3-haiku-20240307
Common fast models:
- claude-3-haiku-20240307 (fastest, good for simple commits)
- claude-3-sonnet-20240229 (balanced speed and quality)
- claude-3-opus-20240229 (highest quality, slower)
Examples:
$0 # Improve last commit with default model
$0 --model claude-3-haiku-20240307 # Use Haiku (fast) model
$0 --branch -m claude-3-haiku-20240307 # Improve branch with Haiku
git ic # After installing aliases
git ib # After installing aliases
This script uses Claude CLI to analyze your commits and suggest better,
more descriptive commit messages.
EOF
;;
"")
# No arguments - default to improving last commit
improve_last_commit
;;
*)
print_colour $RED "Error: Invalid option '${1}'. Use --help for usage information."
exit 1
;;
esac
}
# Check for git config model setting
if [ -z "$CLAUDE_MODEL" ]; then
GIT_MODEL=$(git config --get commit.claude-model 2>/dev/null || echo "")
if [ -n "$GIT_MODEL" ]; then
CLAUDE_MODEL="$GIT_MODEL"
fi
fi
# Check for environment variable
if [ -n "$CLAUDE_MODEL_ENV" ]; then
CLAUDE_MODEL="$CLAUDE_MODEL_ENV"
fi
# Run main function
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment