Created
December 14, 2025 21:27
-
-
Save taheri24/dde9a26b2b33a8ebbebc7c8d4d1debf9 to your computer and use it in GitHub Desktop.
git-ai: AI-Powered Git Analysis with Claude CLI - Smart Code Reviews, Commit Messages & Security Audits
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # git-ai - AI-powered git analysis using claude-cli with custom prompts | |
| # Usage: git-ai <command> [prompt-file] [git-diff-args] | |
| set -euo pipefail | |
| # ═══════════════════════════════════════════════════════════════ | |
| # CONFIGURATION | |
| # ═══════════════════════════════════════════════════════════════ | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| PROMPTS_DIR="${PROMPTS_DIR:-$SCRIPT_DIR/prompts}" | |
| DEFAULT_DIFF_CMD="git diff --staged" | |
| # Colors | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' # No Color | |
| # ═══════════════════════════════════════════════════════════════ | |
| # HELPER FUNCTIONS | |
| # ═══════════════════════════════════════════════════════════════ | |
| error() { | |
| echo -e "${RED}Error: $1${NC}" >&2 | |
| exit 1 | |
| } | |
| info() { | |
| echo -e "${BLUE}ℹ $1${NC}" >&2 | |
| } | |
| success() { | |
| echo -e "${GREEN}✓ $1${NC}" >&2 | |
| } | |
| warn() { | |
| echo -e "${YELLOW}⚠ $1${NC}" >&2 | |
| } | |
| usage() { | |
| cat << 'EOF' | |
| git-ai - AI-powered git analysis using claude-cli | |
| USAGE: | |
| git-ai <command> [prompt-file] [git-diff-args] | |
| git-ai --prompt <prompt-file> [git-diff-args] | |
| git-ai --help | |
| COMMANDS: | |
| analyze - Analyze code changes for bugs and improvements | |
| review - Review staged changes for quality and security | |
| genmsg - Generate conventional commit message | |
| security - Security audit of changes | |
| patchgroup - Group files by commit message (markdown) | |
| summarize - Summarize recent commits | |
| changelog - Generate changelog from commits | |
| testgaps - Identify missing test cases | |
| refactor - Suggest refactoring opportunities | |
| perf - Performance review | |
| pr-desc - Generate PR description | |
| filehistory - Analyze file history (requires file path) | |
| OPTIONS: | |
| -p, --prompt FILE Use custom prompt file | |
| -d, --diff CMD Custom git diff command (default: git diff --staged) | |
| -o, --output FILE Save output to file | |
| -n, --no-diff Don't append git diff (use prompt only) | |
| -h, --help Show this help | |
| EXAMPLES: | |
| # Use built-in command | |
| git-ai analyze | |
| git-ai review | |
| git-ai genmsg | |
| # Use custom prompt file | |
| git-ai --prompt prompts/custom.txt | |
| git-ai -p my-prompt.txt | |
| # Custom git diff command | |
| git-ai analyze --diff "git diff HEAD~1" | |
| git-ai -p prompts/review.txt -d "git diff main...HEAD" | |
| # Group patch files | |
| git-ai patchgroup | |
| git-ai patchgroup -d "git format-patch -1 HEAD --stdout" | |
| # Save output | |
| git-ai analyze -o analysis.md | |
| # Just use prompt without git diff | |
| git-ai --prompt prompts/question.txt --no-diff | |
| PROMPT FILES: | |
| Prompt files should be plain text files containing the instruction | |
| for Claude. The git diff output will be appended automatically unless | |
| --no-diff is used. | |
| Default prompt location: $PROMPTS_DIR | |
| SETUP: | |
| 1. Create prompts directory: mkdir -p prompts | |
| 2. Add prompt files (see examples below) | |
| 3. Make script executable: chmod +x git-ai | |
| 4. Optional: ln -s $(pwd)/git-ai /usr/local/bin/git-ai | |
| EOF | |
| } | |
| check_dependencies() { | |
| command -v claude >/dev/null 2>&1 || error "claude-cli not found. Install from: https://github.com/anthropics/claude-cli" | |
| command -v git >/dev/null 2>&1 || error "git not found" | |
| } | |
| ensure_prompts_dir() { | |
| if [[ ! -d "$PROMPTS_DIR" ]]; then | |
| info "Creating prompts directory: $PROMPTS_DIR" | |
| mkdir -p "$PROMPTS_DIR" | |
| create_default_prompts | |
| fi | |
| } | |
| get_prompt_file() { | |
| local cmd="$1" | |
| echo "$PROMPTS_DIR/${cmd}.txt" | |
| } | |
| # ═══════════════════════════════════════════════════════════════ | |
| # CREATE DEFAULT PROMPT FILES | |
| # ═══════════════════════════════════════════════════════════════ | |
| create_default_prompts() { | |
| info "Creating default prompt files..." | |
| # analyze.txt | |
| cat > "$PROMPTS_DIR/analyze.txt" << 'EOF' | |
| Analyze these code changes. Identify: | |
| - Potential bugs | |
| - Code quality issues | |
| - Performance concerns | |
| - Security vulnerabilities | |
| - Best practice violations | |
| - Improvement suggestions | |
| Be concise and specific. Focus on actionable feedback. | |
| EOF | |
| # review.txt | |
| cat > "$PROMPTS_DIR/review.txt" << 'EOF' | |
| Review these staged changes for: | |
| 1. Code quality and readability | |
| 2. Potential bugs and edge cases | |
| 3. Security issues | |
| 4. Performance implications | |
| 5. Test coverage needs | |
| 6. Documentation requirements | |
| Provide specific, actionable feedback. | |
| EOF | |
| # genmsg.txt | |
| cat > "$PROMPTS_DIR/genmsg.txt" << 'EOF' | |
| Generate a git commit message following conventional commits format. | |
| Format: | |
| <type>: <subject> (max 50 chars) | |
| <body - what and why, if needed> | |
| Types: feat, fix, docs, style, refactor, test, chore, perf | |
| Output ONLY the commit message. No explanations, no markdown, no extra text. | |
| EOF | |
| # security.txt | |
| cat > "$PROMPTS_DIR/security.txt" << 'EOF' | |
| Perform a security audit. Check for: | |
| - Hardcoded secrets, API keys, passwords | |
| - SQL injection vulnerabilities | |
| - XSS vulnerabilities | |
| - Command injection risks | |
| - Path traversal issues | |
| - Insecure cryptography | |
| - Authentication/authorization flaws | |
| - Exposed sensitive data | |
| - CORS misconfigurations | |
| - Dependency vulnerabilities | |
| List findings with severity (HIGH/MEDIUM/LOW). | |
| EOF | |
| # patchgroup.txt | |
| cat > "$PROMPTS_DIR/patchgroup.txt" << 'EOF' | |
| Parse this git patch and group files by commit message. | |
| Output format (markdown only, no descriptions): | |
| ## <Commit Message 1> | |
| - path/to/file1.ext | |
| - path/to/file2.ext | |
| ## <Commit Message 2> | |
| - path/to/file3.ext | |
| Rules: | |
| - Commit messages as ## headings | |
| - Files as bullet points (-) | |
| - No explanations or additional text | |
| - One file per line | |
| - Preserve exact file paths | |
| - If no commit message exists, use "## Uncommitted Changes" | |
| EOF | |
| # summarize.txt | |
| cat > "$PROMPTS_DIR/summarize.txt" << 'EOF' | |
| Summarize these commits. Group by: | |
| - Features (new functionality) | |
| - Bug Fixes | |
| - Refactoring | |
| - Documentation | |
| - Other | |
| Be concise. Focus on what was accomplished. | |
| EOF | |
| # changelog.txt | |
| cat > "$PROMPTS_DIR/changelog.txt" << 'EOF' | |
| Generate a CHANGELOG.md entry from these commits. | |
| Format: | |
| ## [Version] - Date | |
| ### Added | |
| - New features | |
| ### Fixed | |
| - Bug fixes | |
| ### Changed | |
| - Changes to existing functionality | |
| ### Breaking Changes | |
| - Breaking changes (if any) | |
| Use conventional commit messages to categorize. | |
| EOF | |
| # testgaps.txt | |
| cat > "$PROMPTS_DIR/testgaps.txt" << 'EOF' | |
| Analyze these code changes and identify what tests should be added. | |
| List: | |
| 1. Unit tests needed | |
| 2. Integration tests needed | |
| 3. Edge cases to cover | |
| 4. Error scenarios to test | |
| 5. Missing test coverage | |
| Be specific about what to test and why. | |
| EOF | |
| # refactor.txt | |
| cat > "$PROMPTS_DIR/refactor.txt" << 'EOF' | |
| Suggest refactoring opportunities: | |
| - DRY violations (code duplication) | |
| - Long functions (>50 lines) | |
| - Complex conditionals | |
| - Magic numbers/strings | |
| - Poor naming | |
| - Tight coupling | |
| - Missing abstractions | |
| - Code smells | |
| Provide specific suggestions with examples. | |
| EOF | |
| # perf.txt | |
| cat > "$PROMPTS_DIR/perf.txt" << 'EOF' | |
| Performance review. Identify: | |
| - Inefficient algorithms (O(n²) or worse) | |
| - N+1 query problems | |
| - Unnecessary loops | |
| - Memory leaks | |
| - Heavy computations in loops | |
| - Missing caching opportunities | |
| - Blocking operations | |
| - Database query optimization needs | |
| Suggest specific optimizations. | |
| EOF | |
| # pr-desc.txt | |
| cat > "$PROMPTS_DIR/pr-desc.txt" << 'EOF' | |
| Generate a Pull Request description. | |
| Format: | |
| ## What | |
| Brief description of changes | |
| ## Why | |
| Motivation and context | |
| ## How | |
| Technical approach | |
| ## Testing | |
| How to test these changes | |
| ## Screenshots (if UI changes) | |
| Mention if screenshots needed | |
| Be clear and concise. | |
| EOF | |
| # filehistory.txt | |
| cat > "$PROMPTS_DIR/filehistory.txt" << 'EOF' | |
| Summarize the evolution of this file: | |
| - Major changes over time | |
| - Why changes were made | |
| - Patterns in modifications | |
| - Key contributors (if visible) | |
| - Current state vs original | |
| Provide a narrative of the file's development. | |
| EOF | |
| success "Created default prompts in $PROMPTS_DIR" | |
| } | |
| # ═══════════════════════════════════════════════════════════════ | |
| # MAIN LOGIC | |
| # ═══════════════════════════════════════════════════════════════ | |
| main() { | |
| check_dependencies | |
| if [[ $# -eq 0 ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then | |
| usage | |
| exit 0 | |
| fi | |
| ensure_prompts_dir | |
| local command="" | |
| local prompt_file="" | |
| local diff_cmd="$DEFAULT_DIFF_CMD" | |
| local output_file="" | |
| local use_diff=true | |
| # Parse arguments | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| -p|--prompt) | |
| prompt_file="$2" | |
| shift 2 | |
| ;; | |
| -d|--diff) | |
| diff_cmd="$2" | |
| shift 2 | |
| ;; | |
| -o|--output) | |
| output_file="$2" | |
| shift 2 | |
| ;; | |
| -n|--no-diff) | |
| use_diff=false | |
| shift | |
| ;; | |
| -h|--help) | |
| usage | |
| exit 0 | |
| ;; | |
| analyze|review|genmsg|security|patchgroup|summarize|changelog|testgaps|refactor|perf|pr-desc|filehistory) | |
| command="$1" | |
| shift | |
| ;; | |
| *) | |
| error "Unknown option: $1\nUse --help for usage information" | |
| ;; | |
| esac | |
| done | |
| # Determine prompt file | |
| if [[ -n "$prompt_file" ]]; then | |
| [[ -f "$prompt_file" ]] || error "Prompt file not found: $prompt_file" | |
| elif [[ -n "$command" ]]; then | |
| prompt_file=$(get_prompt_file "$command") | |
| [[ -f "$prompt_file" ]] || error "Prompt file not found: $prompt_file\nRun with --help to see available commands" | |
| else | |
| error "No command or prompt file specified\nUse --help for usage information" | |
| fi | |
| info "Using prompt: $prompt_file" | |
| info "Diff command: $diff_cmd" | |
| # Read prompt | |
| local prompt | |
| prompt=$(<"$prompt_file") | |
| # Get git diff if needed | |
| local git_output="" | |
| if [[ "$use_diff" == true ]]; then | |
| info "Running: $diff_cmd" | |
| if ! git_output=$(eval "$diff_cmd" 2>&1); then | |
| error "Git command failed: $diff_cmd" | |
| fi | |
| if [[ -z "$git_output" ]]; then | |
| warn "No diff output. Check if you have staged changes or adjust --diff command" | |
| exit 0 | |
| fi | |
| fi | |
| # Combine prompt and git output | |
| local full_prompt | |
| if [[ "$use_diff" == true ]]; then | |
| full_prompt=$(cat << EOF | |
| $prompt | |
| --- | |
| $git_output | |
| EOF | |
| ) | |
| else | |
| full_prompt="$prompt" | |
| fi | |
| # Run claude | |
| info "Running claude-cli..." | |
| local result | |
| if ! result=$(echo "$full_prompt" | claude -p); then | |
| error "claude-cli failed" | |
| fi | |
| # Output | |
| if [[ -n "$output_file" ]]; then | |
| echo "$result" > "$output_file" | |
| success "Output saved to: $output_file" | |
| else | |
| echo "$result" | |
| fi | |
| } | |
| # ═══════════════════════════════════════════════════════════════ | |
| # RUN | |
| # ═══════════════════════════════════════════════════════════════ | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment