"""Git utilities for HYDRA autoresearch branch management.""" import os import subprocess REPO_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def run_git(*args: str, check: bool = True) -> subprocess.CompletedProcess: """Run a git command in the repo directory. Args: *args: Git command arguments. check: Whether to raise on non-zero exit code. Returns: Completed process with stdout/stderr captured. """ return subprocess.run( ["git"] + list(args), cwd=REPO_DIR, capture_output=True, text=True, check=check, ) def current_branch() -> str: """Return the current git branch name. Returns: Branch name string. """ result = run_git("rev-parse", "--abbrev-ref", "HEAD") return result.stdout.strip() def current_commit_short() -> str: """Return the current HEAD commit short hash (7 chars). Returns: 7-character commit hash. """ result = run_git("rev-parse", "--short=7", "HEAD") return result.stdout.strip() def create_branch(name: str) -> None: """Create and switch to a new branch. Args: name: Branch name to create. """ run_git("checkout", "-b", name) def commit_all(message: str) -> str: """Stage all changes, commit, and return short hash. Args: message: Commit message. Returns: Short commit hash after committing. """ run_git("add", "-A") run_git("commit", "-m", message, check=False) return current_commit_short() def reset_to(commit: str) -> None: """Hard reset to a specific commit, discarding all changes. Args: commit: Commit hash (short or full) to reset to. """ run_git("reset", "--hard", commit) def get_last_n_diffs(n: int = 3) -> list[str]: """Get the last N commit diffs (--stat format) for meta-agent context. Args: n: Number of recent commits to retrieve. Returns: List of diff stat strings, one per commit (truncated to 500 chars). """ result = run_git("log", f"-{n}", "--format=%H", check=False) hashes = [h for h in result.stdout.strip().split("\n") if h] diffs: list[str] = [] for h in hashes: diff_result = run_git("show", "--stat", h, check=False) diffs.append(diff_result.stdout[:500]) return diffs