authorgravatar for 269035359+t3-code[bot]@users.noreply.github.comt3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com> 2026-08-10 23:34:18-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-10 23:34:18-04:00
log9c7622dac3d1a385351e6c74354a9e6b9c2037d5
treeb17cbdbf114c6972129dddd4344b8c4587d2c5e3
parentc14bcca1035895edca5ebd8d65faea5fe788a825
signature Signed by PGP key B5690EEEBB952194

fix(server): handle unborn HEAD in VCS status (#5944)

Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>

2 files changed, 41 insertions(+), 14 deletions(-)

apps/server/src/vcs/GitVcsDriverCore.test.ts+17
......@@ -1001,6 +1001,23 @@ it.layer(TestLayer)("GitVcsDriver core integration", (it) => {
10011001 }),
10021002 );
10031003
1004 it.effect("reports remote status on unborn HEAD without failing", () =>
1005 Effect.gen(function* () {
1006 const cwd = yield* makeTmpDir();
1007 const driver = yield* GitVcsDriver.GitVcsDriver;
1008 yield* driver.initRepo({ cwd });
1009 const initialBranch = yield* git(cwd, ["symbolic-ref", "--short", "HEAD"]);
1010
1011 const status = yield* driver.statusDetailsRemote(cwd, { refreshUpstream: false });
1012
1013 assert.equal(status.isRepo, true);
1014 assert.equal(status.branch, initialBranch);
1015 assert.equal(status.hasUpstream, false);
1016 assert.equal(status.aheadCount, 0);
1017 assert.equal(status.behindCount, 0);
1018 }),
1019 );
1020
10041021 it.effect("can read cached remote divergence without fetching upstream", () =>
10051022 Effect.gen(function* () {
10061023 const cwd = yield* makeTmpDir();
apps/server/src/vcs/GitVcsDriverCore.ts+24-14
......@@ -1477,25 +1477,35 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
14771477 if (branchResult === null) {
14781478 return NON_REPOSITORY_REMOTE_STATUS_DETAILS;
14791479 }
1480 let branch: string | null;
14801481 if (branchResult.exitCode !== 0) {
14811482 if (isNonRepositoryGitStderr(branchResult.stderr)) {
14821483 return NON_REPOSITORY_REMOTE_STATUS_DETAILS;
14831484 }
1484 return yield* new GitCommandError({
1485 ...gitCommandContext({
1486 operation: "GitVcsDriver.statusDetailsRemote.branch",
1487 cwd,
1488 args: ["rev-parse", "--abbrev-ref", "HEAD"],
1489 }),
1490 detail: "Git branch lookup failed.",
1491 exitCode: branchResult.exitCode,
1492 stdoutLength: branchResult.stdout.length,
1493 stderrLength: branchResult.stderr.length,
1494 });
1495 }
1485 if (!isUnbornHeadStderr(branchResult.stderr)) {
1486 return yield* new GitCommandError({
1487 ...gitCommandContext({
1488 operation: "GitVcsDriver.statusDetailsRemote.branch",
1489 cwd,
1490 args: ["rev-parse", "--abbrev-ref", "HEAD"],
1491 }),
1492 detail: "Git branch lookup failed.",
1493 exitCode: branchResult.exitCode,
1494 stdoutLength: branchResult.stdout.length,
1495 stderrLength: branchResult.stderr.length,
1496 });
1497 }
14961498
1497 const branchValue = branchResult.stdout.trim();
1498 const branch = branchValue.length > 0 && branchValue !== "HEAD" ? branchValue : null;
1499 const branchValue = yield* runGitStdout(
1500 "GitVcsDriver.statusDetailsRemote.unbornBranch",
1501 cwd,
1502 ["symbolic-ref", "--quiet", "--short", "HEAD"],
1503 );
1504 branch = branchValue.trim() || null;
1505 } else {
1506 const branchValue = branchResult.stdout.trim();
1507 branch = branchValue.length > 0 && branchValue !== "HEAD" ? branchValue : null;
1508 }
14991509 const upstream = yield* resolveCurrentUpstream(cwd);
15001510 const upstreamRef = upstream?.upstreamRef ?? null;
15011511 let aheadCount = 0;