Skip to content

Commit 1d5a8bf

Browse files
committed
fix(server): strip linked worktree markers from branch list
1 parent 335bf1e commit 1d5a8bf

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

packages/server/src/__tests__/git/cli.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,10 +432,12 @@ describe("GitError", () => {
432432
describe("runGitListBranches", () => {
433433
let testDir: string;
434434
let remoteDir: string;
435+
let linkedWorktreeDir: string;
435436

436437
beforeEach(async () => {
437438
testDir = join(tmpdir(), `git-test-${Date.now()}`);
438439
remoteDir = join(tmpdir(), `git-remote-${Date.now()}`);
440+
linkedWorktreeDir = join(tmpdir(), `git-linked-worktree-${Date.now()}`);
439441
await mkdir(testDir);
440442

441443
// Initialize git repo
@@ -455,6 +457,11 @@ describe("runGitListBranches", () => {
455457
} catch {
456458
// Ignore cleanup errors
457459
}
460+
try {
461+
await rmdir(linkedWorktreeDir, { recursive: true });
462+
} catch {
463+
// Ignore cleanup errors
464+
}
458465
});
459466

460467
it("returns structured branch data with remote branches", async () => {
@@ -601,6 +608,33 @@ describe("runGitListBranches", () => {
601608

602609
await rm(testDir, { recursive: true });
603610
});
611+
612+
it("strips linked worktree markers from local branch names", async () => {
613+
await writeFile(join(testDir, "README.md"), "test");
614+
await execFileAsync("git", ["add", "."], { cwd: testDir });
615+
await execFileAsync("git", ["commit", "-m", "initial"], { cwd: testDir });
616+
617+
const defaultBranch = await getCurrentBranch(testDir);
618+
await execFileAsync("git", ["branch", "feature/worktree-branch"], { cwd: testDir });
619+
await execFileAsync("git", ["worktree", "add", linkedWorktreeDir, "feature/worktree-branch"], {
620+
cwd: testDir,
621+
});
622+
623+
const { runGitListBranches } = await import("../../git/cli.js");
624+
const result = await runGitListBranches(testDir);
625+
626+
expect(result.current).toBe(defaultBranch);
627+
expect(result.branches).toContainEqual({
628+
name: "feature/worktree-branch",
629+
isRemote: false,
630+
isCurrent: false,
631+
});
632+
expect(result.branches).not.toContainEqual(
633+
expect.objectContaining({
634+
name: expect.stringMatching(/^\+\s/),
635+
})
636+
);
637+
});
604638
});
605639

606640
describe("getGitStatus", () => {

packages/server/src/git/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ export async function runGitListBranches(cwd: string): Promise<{
655655
const localLines = localOutput.split("\n").filter((line) => line.trim());
656656
for (const line of localLines) {
657657
const isCurrent = line.startsWith("*");
658-
const name = line.replace(/^\*?\s+/, "").trim();
658+
const name = line.replace(/^[*+ ]\s+/, "").trim();
659659

660660
// Skip detached HEAD indicator
661661
if (name.startsWith("(HEAD detached")) {

0 commit comments

Comments
 (0)