authorgravatar for github@edm115.devEDM115 <github@edm115.dev> 2026-04-01 03:02:09+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-31 18:02:09-07:00
log19eb9e7227b2daad4e77fc2ae91814c1dae0875d
tree4fc46ddf357ee1f08816ca5a1d8e9cc0d40ecdc2
parentaa5521dcfb709ddd3f3d079e70efb71916e74fe4
signature Signed by PGP key B5690EEEBB952194

fix(server): parse git branches correctly when column.ui is enabled (#1529)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

2 files changed, 63 insertions(+), 4 deletions(-)

apps/server/src/git/Layers/GitCore.test.ts+59-1
...@@ -369,6 +369,64 @@ it.layer(TestLayer)("git integration", (it) => {...@@ -369,6 +369,64 @@ it.layer(TestLayer)("git integration", (it) => {
369 }),369 }),
370 );370 );
371371
372 it.effect("parses separate branch names when column.ui is always enabled", () =>
373 Effect.gen(function* () {
374 const tmp = yield* makeTmpDir();
375 const { initialBranch } = yield* initRepoWithCommit(tmp);
376 const createdBranchNames = [
377 "go-bin",
378 "copilot/rewrite-cli-in-go",
379 "copilot/rewrite-cli-in-rust",
380 ] as const;
381 for (const branchName of createdBranchNames) {
382 yield* (yield* GitCore).createBranch({ cwd: tmp, branch: branchName });
383 }
384 yield* git(tmp, ["config", "column.ui", "always"]);
385
386 const rawBranchOutput = yield* git(tmp, ["branch", "--no-color"], {
387 ...process.env,
388 COLUMNS: "120",
389 });
390 expect(
391 rawBranchOutput
392 .split("\n")
393 .some(
394 (line) =>
395 createdBranchNames.filter((branchName) => line.includes(branchName)).length >= 2,
396 ),
397 ).toBe(true);
398
399 const realGitCore = yield* GitCore;
400 const core = yield* makeIsolatedGitCore((input) =>
401 realGitCore.execute(
402 input.args[0] === "branch"
403 ? {
404 ...input,
405 env: { ...input.env, COLUMNS: "120" },
406 }
407 : input,
408 ),
409 );
410
411 const result = yield* core.listBranches({ cwd: tmp });
412 const localBranchNames = result.branches
413 .filter((branch) => !branch.isRemote)
414 .map((branch) => branch.name);
415
416 expect(localBranchNames).toHaveLength(4);
417 expect(localBranchNames).toEqual(
418 expect.arrayContaining([initialBranch, ...createdBranchNames]),
419 );
420 expect(
421 localBranchNames.some(
422 (branchName) =>
423 createdBranchNames.filter((createdBranch) => branchName.includes(createdBranch))
424 .length >= 2,
425 ),
426 ).toBe(false);
427 }),
428 );
429
372 it.effect("isDefault is false when no remote exists", () =>430 it.effect("isDefault is false when no remote exists", () =>
373 Effect.gen(function* () {431 Effect.gen(function* () {
374 const tmp = yield* makeTmpDir();432 const tmp = yield* makeTmpDir();
...@@ -1898,7 +1956,7 @@ it.layer(TestLayer)("git integration", (it) => {...@@ -1898,7 +1956,7 @@ it.layer(TestLayer)("git integration", (it) => {
1898 let didFailRemoteBranches = false;1956 let didFailRemoteBranches = false;
1899 let didFailRemoteNames = false;1957 let didFailRemoteNames = false;
1900 const core = yield* makeIsolatedGitCore((input) => {1958 const core = yield* makeIsolatedGitCore((input) => {
1901 if (input.args.join(" ") === "branch --no-color --remotes") {1959 if (input.args.join(" ") === "branch --no-color --no-column --remotes") {
1902 didFailRemoteBranches = true;1960 didFailRemoteBranches = true;
1903 return Effect.fail(1961 return Effect.fail(
1904 new GitCommandError({1962 new GitCommandError({
apps/server/src/git/Layers/GitCore.ts+4-3
...@@ -1566,7 +1566,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {...@@ -1566,7 +1566,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {
1566 const localBranchResult = yield* executeGit(1566 const localBranchResult = yield* executeGit(
1567 "GitCore.listBranches.branchNoColor",1567 "GitCore.listBranches.branchNoColor",
1568 input.cwd,1568 input.cwd,
1569 ["branch", "--no-color"],1569 ["branch", "--no-color", "--no-column"],
1570 {1570 {
1571 timeoutMs: 10_000,1571 timeoutMs: 10_000,
1572 allowNonZeroExit: true,1572 allowNonZeroExit: true,
...@@ -1581,7 +1581,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {...@@ -1581,7 +1581,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {
1581 return yield* createGitCommandError(1581 return yield* createGitCommandError(
1582 "GitCore.listBranches",1582 "GitCore.listBranches",
1583 input.cwd,1583 input.cwd,
1584 ["branch", "--no-color"],1584 ["branch", "--no-color", "--no-column"],
1585 stderr || "git branch failed",1585 stderr || "git branch failed",
1586 );1586 );
1587 }1587 }
...@@ -1589,7 +1589,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {...@@ -1589,7 +1589,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {
1589 const remoteBranchResultEffect = executeGit(1589 const remoteBranchResultEffect = executeGit(
1590 "GitCore.listBranches.remoteBranches",1590 "GitCore.listBranches.remoteBranches",
1591 input.cwd,1591 input.cwd,
1592 ["branch", "--no-color", "--remotes"],1592 ["branch", "--no-color", "--no-column", "--remotes"],
1593 {1593 {
1594 timeoutMs: 10_000,1594 timeoutMs: 10_000,
1595 allowNonZeroExit: true,1595 allowNonZeroExit: true,
...@@ -1957,6 +1957,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {...@@ -1957,6 +1957,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {
1957 runGitStdout("GitCore.listLocalBranchNames", cwd, [1957 runGitStdout("GitCore.listLocalBranchNames", cwd, [
1958 "branch",1958 "branch",
1959 "--list",1959 "--list",
1960 "--no-column",
1960 "--format=%(refname:short)",1961 "--format=%(refname:short)",
1961 ]).pipe(1962 ]).pipe(
1962 Effect.map((stdout) =>1963 Effect.map((stdout) =>