diff --git a/packages/server/src/utils/checkout-git.test.ts b/packages/server/src/utils/checkout-git.test.ts index c28586d8a..9c319ca54 100644 --- a/packages/server/src/utils/checkout-git.test.ts +++ b/packages/server/src/utils/checkout-git.test.ts @@ -315,18 +315,28 @@ describe("checkout git utilities", () => { }); }); - it("reports a real non-git directory as non-git", async () => { + it("reports an ordinary directory as non-git without warning", async () => { const nonGitDir = join(tempDir, "not-git-status"); mkdirSync(nonGitDir, { recursive: true }); + const records: unknown[] = []; + const logger = pino( + { level: "warn" }, + { + write(line: string) { + records.push(JSON.parse(line)); + }, + }, + ); - await expect(getCheckoutStatus(nonGitDir)).resolves.toEqual({ isGit: false }); + await expect(getCheckoutStatus(nonGitDir, { logger })).resolves.toEqual({ isGit: false }); + expect(records).toEqual([]); }); it.runIf( process.platform !== "win32" && existsSync("/dev/shm") && statSync("/dev").dev !== statSync("/dev/shm").dev, - )("warns and reports a non-git directory at a filesystem boundary as non-git", async () => { + )("does not warn for a non-git directory at a filesystem boundary", async () => { const nonGitDir = realpathSync.native(mkdtempSync("/dev/shm/checkout-git-boundary-test-")); const records: unknown[] = []; const logger = pino( @@ -339,21 +349,34 @@ describe("checkout git utilities", () => { ); try { await expect(getCheckoutStatus(nonGitDir, { logger })).resolves.toEqual({ isGit: false }); - expect(records).toEqual([ - expect.objectContaining({ - level: 40, - cwd: nonGitDir, - msg: "Git worktree discovery failed; treating directory as non-Git", - err: expect.objectContaining({ - message: expect.stringContaining("Stopping at filesystem boundary"), - }), - }), - ]); + expect(records).toEqual([]); } finally { rmSync(nonGitDir, { recursive: true, force: true }); } }); + it("warns when git discovery fails unexpectedly", async () => { + const missingDir = join(tempDir, "missing-git-cwd"); + const records: unknown[] = []; + const logger = pino( + { level: "warn" }, + { + write(line: string) { + records.push(JSON.parse(line)); + }, + }, + ); + + await expect(getCheckoutStatus(missingDir, { logger })).resolves.toEqual({ isGit: false }); + expect(records).toEqual([ + expect.objectContaining({ + level: 40, + cwd: missingDir, + msg: "Git worktree discovery failed; treating directory as non-Git", + }), + ]); + }); + it("returns null for getCurrentBranch in a repo with no commits", async () => { const emptyRepo = join(tempDir, "empty-repo"); mkdirSync(emptyRepo, { recursive: true }); diff --git a/packages/server/src/utils/checkout-git.ts b/packages/server/src/utils/checkout-git.ts index 1b0752ede..ed026e70c 100644 --- a/packages/server/src/utils/checkout-git.ts +++ b/packages/server/src/utils/checkout-git.ts @@ -810,6 +810,10 @@ export type CheckoutSnapshotFacts = pullRequestLookupTarget: PullRequestStatusLookupTarget | null; }; +function isNotGitRepositoryError(error: unknown): boolean { + return error instanceof Error && /not a git repository/i.test(error.message); +} + async function requireGitRepo(cwd: string): Promise { try { await runGitCommand(["rev-parse", "--git-dir"], { cwd, envOverlay: READ_ONLY_GIT_ENV }); @@ -897,11 +901,12 @@ async function getWorktreeRoot(cwd: string, context?: CheckoutContext): Promise< }); return parseGitRevParsePath(stdout); } catch (error) { - // Git discovery is fail-open: keep the directory usable as non-Git and retain the diagnostic. - context?.logger?.warn( - { err: error, cwd }, - "Git worktree discovery failed; treating directory as non-Git", - ); + if (!isNotGitRepositoryError(error)) { + context?.logger?.warn( + { err: error, cwd }, + "Git worktree discovery failed; treating directory as non-Git", + ); + } return null; } }