Skip to content

AI commit message generator. Conventional commits, compose mode, and history rewrite via Claude/GPT APIs.

License

Notifications You must be signed in to change notification settings

can1357/llm-git

Repository files navigation

llm-git

CI Crates.io License: MIT Rust Version

Git commit message generator using Claude AI (or other LLMs) via OpenAI-compatible API. Generates conventional commit messages with concise summaries (≤72 chars) and structured detail points from git diffs.

Two-phase generation:

  1. Analysis phase: Extract 0-6 detail points from diff using Sonnet/Opus
  2. Summary phase: Generate commit summary from details using Haiku

Installation

Prerequisites

From Source

git clone https://github.com/can1357/llm-git.git
cd llm-git
cargo install --path .

From crates.io

Once published:

cargo install llm-git

Quick Start

Configure API Access

Option A: LiteLLM (Recommended for local development)

# Start LiteLLM proxy (handles API keys and routing)
pip install litellm
export ANTHROPIC_API_KEY=your_key_here
litellm --port 4000 --model claude-sonnet-4.5

# llm-git uses localhost:4000 by default
llm-git  # Ready to use!

Option B: Direct API Access

# Set API URL and key via environment variables
export LLM_GIT_API_URL=https://api.anthropic.com/v1
export LLM_GIT_API_KEY=your_api_key_here
llm-git

Option C: OpenRouter

export LLM_GIT_API_URL=https://openrouter.ai/api/v1
export LLM_GIT_API_KEY=your_openrouter_key
llm-git

Option D: Configuration File

# Create ~/.config/llm-git/config.toml (see Configuration section)
mkdir -p ~/.config/llm-git
# Edit config.toml with your preferences
llm-git

Usage

# Stage your changes
git add .

# Generate and commit
llm-git                                     # Analyze & commit staged changes
llm-git --dry-run                          # Preview without committing
llm-git --mode=unstaged                    # Analyze unstaged (no commit)
llm-git --copy                             # Copy message to clipboard
llm-git Fixed regression from PR #123      # Add context (trailing text)

Commands

Basic Usage:

llm-git                                     # Analyze & commit staged changes (default)
llm-git --dry-run                          # Preview without committing
llm-git --mode=unstaged                    # Analyze unstaged (no commit)
llm-git --mode=commit --target=HEAD~1      # Analyze specific commit
llm-git --copy                             # Copy message to clipboard
llm-git -m opus                            # Use Opus model (more powerful)
llm-git -m sonnet                          # Use Sonnet model (default)
llm-git Fixed regression from PR #123      # Add context (trailing text)

Compose Mode (Multi-commit generation):

llm-git --compose                          # Compose changes into multiple atomic commits
llm-git --compose --compose-preview        # Preview proposed splits without committing
llm-git --compose --compose-max-commits 5  # Limit number of commits
llm-git --compose --compose-test-after-each # Run tests after each commit

Rewrite Mode (History rewrite to conventional commits):

llm-git --rewrite                          # Rewrite full history (creates backup)
llm-git --rewrite --rewrite-preview 10     # Preview first 10 commits
llm-git --rewrite --rewrite-dry-run        # Preview all without applying
llm-git --rewrite --rewrite-start main~50  # Rewrite last 50 commits only
llm-git --rewrite --rewrite-parallel 20    # Use 20 parallel API calls
llm-git --rewrite --rewrite-hide-old-types # Hide old type/scope tags

Environment Variables

All configuration options can be overridden via environment variables:

  • LLM_GIT_API_URL - API endpoint URL (default: http://localhost:4000)
  • LLM_GIT_API_KEY - API authentication key (default: none)
  • LLM_GIT_CONFIG - Custom config file path (default: ~/.config/llm-git/config.toml)
  • LLM_GIT_VERBOSE - Enable verbose output with JSON structure

Examples:

# Use OpenAI instead of Claude
export LLM_GIT_API_URL=https://api.openai.com/v1
export LLM_GIT_API_KEY=sk-...
llm-git --analysis-model=gpt-4o --summary-model=gpt-4o-mini

# Use custom config location
export LLM_GIT_CONFIG=~/my-project/.llm-git-config.toml
llm-git

# Enable verbose debugging
export LLM_GIT_VERBOSE=1
llm-git

Testing

cargo test                                  # Run all unit tests
cargo test --lib                            # Library tests only

Architecture

Modular library structure:

  • src/lib.rs - Public API exports
  • src/main.rs - CLI entry point
  • src/analysis.rs - Scope candidate extraction
  • src/api/ - OpenRouter/LiteLLM integration with retry logic
  • src/config.rs - Configuration and prompt templates
  • src/diff.rs - Smart diff truncation with priority scoring
  • src/error.rs - Error types
  • src/git.rs - Git command wrappers
  • src/normalization.rs - Unicode normalization, formatting
  • src/types.rs - Type-safe commit types, scopes, summaries
  • src/validation.rs - Commit message validation

Core workflow:

  1. get_git_diff() + get_git_stat() - Extract staged/unstaged/commit changes
  2. smart_truncate_diff() - Priority-based diff truncation when >100KB:
    • Parse into FileDiff structs with priority scoring
    • Source files (rs/py/js) > config > tests > binaries > lock files
    • Excluded files: Cargo.lock, package-lock.json, etc. (see EXCLUDED_FILES)
    • Preserve headers for all files, truncate content proportionally
  3. generate_conventional_analysis() - Call Sonnet/Opus with CONVENTIONAL_ANALYSIS_PROMPT using function calling
  4. generate_summary_from_analysis() - Call Haiku with SUMMARY_PROMPT_TEMPLATE + detail points
  5. post_process_commit_message() - Enforce length limits, punctuation, capitalization
  6. validate_commit_message() - Check past-tense verbs, length, punctuation

Prompts:

  • CONVENTIONAL_ANALYSIS_PROMPT - Extracts 0-6 past-tense detail statements from diff
  • SUMMARY_PROMPT_TEMPLATE - Creates ≤72 char summary from details + stat
  • Both enforce past-tense verbs: added, fixed, updated, refactored, etc.

Smart truncation strategy (src/diff.rs):

  • Shows ALL file headers even under length pressure
  • Distributes remaining space proportionally by priority
  • Keeps diff context (first 15 + last 10 lines per file)
  • Annotates omitted files

Implementation Notes

Dependencies:

  • clap - CLI parsing with derive macros
  • reqwest (blocking) - OpenRouter API via LiteLLM localhost:4000
  • serde + serde_json - Function calling schema + response parsing
  • arboard - Clipboard support for --copy
  • anyhow + thiserror - Error handling

API integration:

  • Uses OpenRouter's function calling API with structured output
  • Two tools: create_conventional_analysis (detail extraction), create_commit_summary (summary creation)
  • Supports trailing text arguments as user context to analysis phase
  • Fallback to fallback_summary() if model calls fail
  • Retry logic with exponential backoff for transient failures

Validation rules:

  • Summary: ≤72 chars (guideline), ≤96 (soft limit), ≤128 (hard limit), past-tense verb, no trailing period
  • Body: Past-tense verbs preferred, ends with periods
  • Warns on present-tense usage but doesn't block

Models:

  • Default: Sonnet 4.5 (claude-sonnet-4.5)
  • Optional: Opus 4.1 (claude-opus-4.1) via --opus
  • Summary creation: Haiku 4.5 (claude-haiku-4-5-20251001) hardcoded

Rewrite Mode Details

Rewrite mode converts entire git histories to conventional commits format:

Workflow:

  1. Extracts commit list via git rev-list --reverse
  2. For each commit: analyzes diff and generates conventional message
  3. Parallel API calls for faster processing
  4. Rebuilds history with git commit-tree:
    • Preserves trees, authors, dates
    • Updates messages only
    • Maintains parent relationships
    • Updates branch ref to new head

Safety:

  • Auto-creates timestamped backup branch
  • --rewrite-preview N / --rewrite-dry-run modes
  • Checks working tree is clean
  • Preserves all commit metadata except message

Cost: ~$0.001-0.005/commit depending on model and diff size

Configuration

Create ~/.config/llm-git/config.toml to customize behavior:

# API Configuration
api_base_url = "http://localhost:4000"           # Override with LLM_GIT_API_URL
api_key = "your-api-key"                         # Optional, override with LLM_GIT_API_KEY

# HTTP Timeouts
request_timeout_secs = 120                       # Request timeout (default: 120s)
connect_timeout_secs = 30                        # Connection timeout (default: 30s)

# Models (supports any OpenAI-compatible API)
analysis_model = "claude-sonnet-4.5"             # Model for analysis phase
summary_model = "claude-haiku-4-5"               # Model for summary phase

# Commit Message Limits
summary_guideline = 72                           # Target length (conventional commits)
summary_soft_limit = 96                          # Triggers retry if exceeded
summary_hard_limit = 128                         # Absolute maximum

# Retry Configuration
max_retries = 3                                  # API retry attempts
initial_backoff_ms = 1000                        # Initial backoff delay

# Diff Processing
max_diff_length = 100000                         # Max diff size before truncation
wide_change_threshold = 0.50                     # Threshold for omitting scope (50%)

# Compose Mode
compose_max_rounds = 5                           # Max rounds for multi-commit generation

# Model Temperature
temperature = 0.2                                # Low for consistency (0.0-1.0)

# File Exclusions
excluded_files = [                               # Files to exclude from diff
    "Cargo.lock",
    "package-lock.json",
    "yarn.lock",
    # ... add more
]

low_priority_extensions = [                      # Low-priority file extensions
    ".lock", ".toml", ".yaml", ".json", ".md",
    # ... add more
]

# Prompt Variants (advanced)
analysis_prompt_variant = "default"             # Prompt template variant
summary_prompt_variant = "default"              # Prompt template variant
exclude_old_message = true                       # Exclude old message in rewrite mode

Configuration Examples

LiteLLM (localhost):

api_base_url = "http://localhost:4000"
# No api_key needed - LiteLLM handles authentication
analysis_model = "claude-sonnet-4.5"
summary_model = "claude-haiku-4-5"

Anthropic Direct:

api_base_url = "https://api.anthropic.com/v1"
api_key = "sk-ant-..."  # Or use LLM_GIT_API_KEY env var
analysis_model = "claude-sonnet-4.5-20250514"
summary_model = "claude-haiku-4-5-20250514"

OpenRouter:

api_base_url = "https://openrouter.ai/api/v1"
api_key = "sk-or-..."
analysis_model = "anthropic/claude-sonnet-4.5"
summary_model = "anthropic/claude-haiku-4-5"

OpenAI:

api_base_url = "https://api.openai.com/v1"
api_key = "sk-..."
analysis_model = "gpt-4o"
summary_model = "gpt-4o-mini"
temperature = 0.3  # OpenAI models may benefit from slightly higher temp

License

MIT

About

AI commit message generator. Conventional commits, compose mode, and history rewrite via Claude/GPT APIs.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages