Skip to content

Instantly share code, notes, and snippets.

@mgsloan
Last active January 17, 2025 07:43
Show Gist options
  • Save mgsloan/f0d69f7071586f9d8dd34cc3c23f246b to your computer and use it in GitHub Desktop.
Save mgsloan/f0d69f7071586f9d8dd34cc3c23f246b to your computer and use it in GitHub Desktop.
Open editor with llm proposed branch name + branch name from first line. Creates branch based on origin/main and cherry-picks commit onto it. Generated by Claude 3.5 sonnet
#!/usr/bin/env python3
import subprocess
import sys
import tempfile
import os
import re
def run_git_command(command, error_message="Git command failed"):
"""
Run a git command and handle errors consistently.
Args:
command (list): Command and arguments to run
error_message (str): Message to include in error if command fails
Returns:
str: Command output
Raises:
subprocess.CalledProcessError: If command fails
"""
result = subprocess.run(
command,
capture_output=True,
text=True,
check=True
)
return result.stdout.strip()
def get_editor():
"""Get the default editor from git config or environment"""
try:
return run_git_command(['git', 'config', 'core.editor'])
except subprocess.CalledProcessError:
return os.environ.get('EDITOR', 'vim')
def edit_branch_name(initial_content):
"""
Open the default editor with initial content and return the edited content
Args:
initial_content (str): Content to pre-fill in the editor
Returns:
str: The edited content after save
"""
editor = get_editor()
with tempfile.NamedTemporaryFile(mode='w+', suffix='.txt') as tf:
# Write initial content
tf.write(initial_content)
tf.flush()
# Open editor
subprocess.run([editor, tf.name], check=True)
# Read back the edited content
tf.seek(0)
return tf.read().strip()
def commit_message_to_branch_name(commit_message):
"""
Convert a commit message to a branch name by:
- Replacing any non-alphanumeric character with a hyphen
- Collapsing multiple hyphens into one
- Removing leading/trailing hyphens
Args:
commit_message (str): The commit message to convert
Returns:
str: The formatted branch name
Examples:
>>> commit_message_to_branch_name("edits_since_last")
'edits-since-last'
>>> commit_message_to_branch_name("Fix: User Auth!!")
'Fix-User-Auth'
"""
# Replace any non-alphanumeric character with a hyphen
name = re.sub(r'[^a-zA-Z0-9]+', '-', commit_message.lower())
# Remove leading/trailing hyphens
return name.strip('-')
def check_and_create_branch():
"""
Check repository status and create a new branch based on the commit message.
Returns:
tuple: (bool, str) - (success status, error message if any)
"""
try:
# Check git status
status_result = run_git_command(
['git', 'status', '--untracked-files=no', '--porcelain']
)
if status_result:
return False, "Repository has uncommitted changes"
# Get the current HEAD commit SHA
current_sha = run_git_command(['git', 'rev-parse', 'HEAD'])
# Get all commits in main branch
main_commits = run_git_command(['git', 'rev-list', 'origin/main']).split('\n')
if current_sha in main_commits:
return False, "HEAD commit is already in main branch"
# Get the current commit message
commit_message = run_git_command(['git', 'log', '-1', '--pretty=%B'])
branch_name = commit_message_to_branch_name(commit_message)
# Generate branch name suggestion using llm
prompt = f"Generate a git branch name (using only alphanumeric characters and hyphens) for this commit message:\n\n{commit_message}\n\nOutput only the branch name, nothing else."
try:
suggested_name = subprocess.run(
['llm', 'prompt', prompt],
capture_output=True,
text=True,
check=True
).stdout.strip()
except subprocess.CalledProcessError as e:
return False, f"Failed to generate branch name using llm: {e.stderr}"
# Open editor for confirmation/modification
final_branch_name = edit_branch_name(suggested_name + "\n" + branch_name)
if not final_branch_name:
return False, "No branch name provided"
# Create and checkout new branch
run_git_command(['git', 'checkout', '-b', final_branch_name, 'origin/main'])
# Cherry-pick the stored commit
run_git_command(['git', 'cherry-pick', current_sha])
return True, f"Successfully created and switched to branch '{final_branch_name}'"
except subprocess.CalledProcessError as e:
return False, f"Git command failed: {e.stderr}"
except Exception as e:
return False, f"Unexpected error: {str(e)}"
if __name__ == "__main__":
success, message = check_and_create_branch()
print(message)
sys.exit(0 if success else 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment