feat: enhance list-branches endpoint to support fetching remote branches

- Updated the list-branches endpoint to accept an optional parameter for including remote branches.
- Implemented logic to fetch and deduplicate remote branches alongside local branches.
- Modified the CreatePRDialog component to utilize the updated API for branch selection, allowing users to select from both local and remote branches.
This commit is contained in:
Shirone
2026-01-14 18:25:31 +01:00
parent 3f8a8db7a5
commit 07593f8704
4 changed files with 102 additions and 14 deletions

View File

@@ -1,5 +1,5 @@
/**
* POST /list-branches endpoint - List all local branches
* POST /list-branches endpoint - List all local branches and optionally remote branches
*
* Note: Git repository validation (isGitRepo, hasCommits) is handled by
* the requireValidWorktree middleware in index.ts
@@ -21,8 +21,9 @@ interface BranchInfo {
export function createListBranchesHandler() {
return async (req: Request, res: Response): Promise<void> => {
try {
const { worktreePath } = req.body as {
const { worktreePath, includeRemote = false } = req.body as {
worktreePath: string;
includeRemote?: boolean;
};
if (!worktreePath) {
@@ -60,6 +61,55 @@ export function createListBranchesHandler() {
};
});
// Fetch remote branches if requested
if (includeRemote) {
try {
// Fetch latest remote refs (silently, don't fail if offline)
try {
await execAsync('git fetch --all --quiet', {
cwd: worktreePath,
timeout: 10000, // 10 second timeout
});
} catch {
// Ignore fetch errors - we'll use cached remote refs
}
// List remote branches
const { stdout: remoteBranchesOutput } = await execAsync(
'git branch -r --format="%(refname:short)"',
{ cwd: worktreePath }
);
const localBranchNames = new Set(branches.map((b) => b.name));
remoteBranchesOutput
.trim()
.split('\n')
.filter((b) => b.trim())
.forEach((name) => {
// Remove any surrounding quotes
const cleanName = name.trim().replace(/^['"]|['"]$/g, '');
// Skip HEAD pointers like "origin/HEAD"
if (cleanName.includes('/HEAD')) return;
// Extract the branch name without the remote prefix for deduplication
// e.g., "origin/main" -> "main"
const branchNameWithoutRemote = cleanName.replace(/^[^/]+\//, '');
// Only add remote branches that don't exist locally (to avoid duplicates)
if (!localBranchNames.has(branchNameWithoutRemote)) {
branches.push({
name: cleanName, // Keep full name like "origin/main"
isCurrent: false,
isRemote: true,
});
}
});
} catch {
// Ignore errors fetching remote branches - return local branches only
}
}
// Get ahead/behind count for current branch
let aheadCount = 0;
let behindCount = 0;