Skip to content

Instantly share code, notes, and snippets.

@leliel12
Last active December 2, 2025 16:38
Show Gist options
  • Select an option

  • Save leliel12/4a15a0d129bea4f6801cc233354659d4 to your computer and use it in GitHub Desktop.

Select an option

Save leliel12/4a15a0d129bea4f6801cc233354659d4 to your computer and use it in GitHub Desktop.
git plugin for autocommit with claude
#!/usr/bin/env python3
"""
Git AI Commit - Automated commit creation using Claude AI
Author: Juan BC
Email: [email protected]
License: BSD-3-Clause
Installation:
1. Copy this script to a directory in your PATH (e.g., ~/.local/bin/)
$ cp git-iacommit ~/.local/bin/
2. Make it executable:
$ chmod +x ~/.local/bin/git-iacommit
3. Ensure ~/.local/bin is in your PATH (add to ~/.bashrc or ~/.zshrc if needed):
export PATH="$HOME/.local/bin:$PATH"
4. Now you can use it as a git subcommand:
$ git iacommit
Requirements:
- Python 3.6+
- Claude CLI installed and configured
- Git repository
"""
import argparse
import subprocess
import sys
PROMPT = """Create a git commit with the staged changes and any relevant unstaged files. Review the changes, write an appropriate commit message following the repository's style, and create the commit.
DO NOT PUSH!
"""
def is_git_repo():
"""Check if the current directory is a Git repository"""
try:
subprocess.run(
["git", "rev-parse", "--git-dir"],
check=True,
capture_output=True,
text=True,
)
return True
except subprocess.CalledProcessError:
return False
def has_changes():
"""Check if there are any staged changes or changes in tracked files"""
try:
# Check for staged changes
staged = subprocess.run(
["git", "diff", "--cached", "--quiet"],
capture_output=True,
)
has_staged = staged.returncode != 0
# Check for changes in tracked files (unstaged)
tracked = subprocess.run(
["git", "diff", "--quiet"],
capture_output=True,
)
has_tracked = tracked.returncode != 0
return has_staged or has_tracked
except subprocess.CalledProcessError:
return False
def get_changes_summary():
"""Get a detailed summary of what changes exist"""
staged_count = 0
unstaged_count = 0
try:
# Count staged changes
result = subprocess.run(
["git", "diff", "--cached", "--numstat"],
check=True,
capture_output=True,
text=True,
)
if result.stdout.strip():
staged_count = len(result.stdout.strip().split('\n'))
# Count unstaged changes in tracked files
result = subprocess.run(
["git", "diff", "--numstat"],
check=True,
capture_output=True,
text=True,
)
if result.stdout.strip():
unstaged_count = len(result.stdout.strip().split('\n'))
except subprocess.CalledProcessError:
pass
return staged_count, unstaged_count
def get_status_summary():
"""Get a summary of git status"""
try:
result = subprocess.run(
["git", "status", "--short"],
check=True,
capture_output=True,
text=True,
)
return result.stdout.strip()
except subprocess.CalledProcessError:
return None
def get_last_commit_message():
"""Get the last commit message"""
try:
result = subprocess.run(
["git", "log", "-1", "--pretty=%B"],
check=True,
capture_output=True,
text=True,
)
return result.stdout.strip()
except subprocess.CalledProcessError:
return None
def run_commit(dry_run=False, verbose=False):
"""Execute Claude to create the commit"""
try:
if verbose:
status = get_status_summary()
if status:
print("πŸ“Š Current repository status:")
print(status)
print()
print("πŸ€– Running Claude to create the commit...")
print()
if dry_run:
print("πŸ” Dry-run mode: Claude will review changes but won't create the commit")
print()
cmd = ["claude", PROMPT, "-p"]
result = subprocess.run(cmd, check=True, text=True)
if result.returncode == 0:
print()
print("βœ… Commit created successfully")
# Display the commit message
commit_message = get_last_commit_message()
if commit_message:
print()
print("πŸ“ Commit message:")
print("-" * 50)
print(commit_message)
print("-" * 50)
return result.returncode
except subprocess.CalledProcessError as e:
print(f"❌ Error running Claude: {e}", file=sys.stderr)
return e.returncode
except FileNotFoundError:
print(
"❌ Error: Claude is not installed or not in PATH",
file=sys.stderr
)
print(" Install Claude CLI from: https://github.com/anthropics/anthropic-tools",
file=sys.stderr)
return 1
except KeyboardInterrupt:
print("\n⚠️ Operation cancelled by user", file=sys.stderr)
return 130
def main():
"""Main function"""
parser = argparse.ArgumentParser(
description="Create commits automatically using Claude AI",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"-v", "--verbose",
action="store_true",
help="Show additional information about the changes"
)
parser.add_argument(
"-n", "--dry-run",
action="store_true",
help="Run without creating the commit (only shows what would be done)"
)
args = parser.parse_args()
# Check if we are in a Git repository
if not is_git_repo():
print("❌ Error: Not in a Git repository", file=sys.stderr)
sys.exit(1)
# Check if there are any changes
if not has_changes():
print("⚠️ No changes to commit", file=sys.stderr)
print(" - No files in staging area", file=sys.stderr)
print(" - No changes in tracked files", file=sys.stderr)
print(" Use 'git add' or modify tracked files", file=sys.stderr)
sys.exit(1)
# Show summary of changes if verbose
if args.verbose:
staged, unstaged = get_changes_summary()
print(f"πŸ“Š Changes detected:")
print(f" - {staged} file(s) in staging")
print(f" - {unstaged} modified file(s) without staging")
print()
# Execute the commit
exit_code = run_commit(dry_run=args.dry_run, verbose=args.verbose)
sys.exit(exit_code)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment