/** * BranchManager Port Interface * * Manages branch-level git operations (create, merge, diff, delete) * across project clones. Works directly on branches without requiring * a worktree to be checked out. */ import type { MergeResult, MergeabilityResult, BranchCommit, FileStatEntry } from './types.js'; export interface BranchManager { /** * Ensure a branch exists. Creates it from baseBranch if it doesn't. * Idempotent — no-op if the branch already exists. */ ensureBranch(repoPath: string, branch: string, baseBranch: string): Promise; /** * Merge sourceBranch into targetBranch. * Uses an ephemeral worktree for merge safety. * Returns conflict info if merge fails. */ mergeBranch(repoPath: string, sourceBranch: string, targetBranch: string): Promise; /** * Get the raw unified diff between two branches. * Uses three-dot diff (baseBranch...headBranch) to show changes * introduced by headBranch since it diverged from baseBranch. */ diffBranches(repoPath: string, baseBranch: string, headBranch: string): Promise; /** * Get per-file metadata for changes between two branches. * Uses three-dot diff (baseBranch...headBranch) — same divergence model as diffBranches. * Binary files are included with status 'binary' and additions/deletions both 0. * Does NOT return hunk content. */ diffBranchesStat(repoPath: string, baseBranch: string, headBranch: string): Promise; /** * Get the raw unified diff for a single file between two branches. * Uses three-dot diff (baseBranch...headBranch). * Returns empty string for binary files (caller must detect binary separately). * filePath must be URL-decoded before being passed here. */ diffFileSingle(repoPath: string, baseBranch: string, headBranch: string, filePath: string): Promise; /** * Delete a branch. No-op if the branch doesn't exist. */ deleteBranch(repoPath: string, branch: string): Promise; /** * Check if a branch exists in the repository. */ branchExists(repoPath: string, branch: string): Promise; /** * Check if a branch exists as a remote tracking branch (origin/). * Useful for validating branch names against what the remote has, * since local branches may not include all remote branches. */ remoteBranchExists(repoPath: string, branch: string): Promise; /** * List commits that headBranch has but baseBranch doesn't. * Used for commit-level navigation in code review. */ listCommits(repoPath: string, baseBranch: string, headBranch: string): Promise; /** * Get the raw unified diff for a single commit. */ diffCommit(repoPath: string, commitHash: string): Promise; /** * Get the merge base (common ancestor) of two branches. * Returns the commit hash of the merge base. */ getMergeBase(repoPath: string, branch1: string, branch2: string): Promise; /** * Push a branch to a remote. * Defaults to 'origin' if no remote specified. */ pushBranch(repoPath: string, branch: string, remote?: string): Promise; /** * Dry-run merge check — determines if sourceBranch can be cleanly merged * into targetBranch without actually performing the merge. * Uses `git merge-tree --write-tree` (git 2.38+). */ checkMergeability(repoPath: string, sourceBranch: string, targetBranch: string): Promise; /** * Fetch all refs from a remote. * Defaults to 'origin' if no remote specified. */ fetchRemote(repoPath: string, remote?: string): Promise; /** * Fast-forward a local branch to match its remote-tracking counterpart. * No-op if already up to date. Throws if fast-forward is not possible * (i.e. the branches have diverged). */ fastForwardBranch(repoPath: string, branch: string, remote?: string): Promise; /** * Force-update a branch ref to point at a specific commit. * Used to roll back a merge when a subsequent push fails. */ updateRef(repoPath: string, branch: string, commitHash: string): Promise; }