Detect git workspaces with rev-parse instead of a .git stat

`isGitRepo` only accepted a `.git` directory, so linked worktrees and
submodules — both of which store `.git` as a file containing
`gitdir: …` — silently fell into the non-git branch. The baseline
diff then replaced `git status` as the source of truth for workspaces
that git itself recognises, and edge cases where the baseline is
missing (a freshly-created worktree mid-run, a submodule without a
captured snapshot) bled into `no_baseline` skips instead of running
the authoritative diff.

Call `git rev-parse --is-inside-work-tree` and take git's own yes/no
answer. Exit 0 means git would happily run `status` there; any other
outcome (no git binary, corrupted ref, genuinely non-git) lands us on
the baseline path exactly as before.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 16:51:44 -04:00
1 parent 1cb7e9fffa
commit f9349f374c
1 file changed
+21 -2
+21 -2
View File
@@ -1,6 +1,6 @@
import { isAbsolute, relative, resolve } from "node:path";
import { execFileSync } from "node:child_process";
import { existsSync, readdirSync, statSync } from "node:fs";
import { readdirSync, statSync } from "node:fs";
import type { AppDatabase } from "@main/database";
/**
@@ -392,9 +392,28 @@ function projectBashArtifacts(
return projectChangedPaths(db, ctx, change.paths);
}
/**
* Ask git whether `workspacePath` sits inside a working tree. This
* covers the three forms the `.git` entry takes in real setups:
*
* - a directory (a plain clone),
* - a file with `gitdir: …` (a linked worktree), or
* - a file with `gitdir: …/modules/…` (a submodule).
*
* The previous `existsSync + isDirectory` probe only recognised the
* first form, so linked worktrees and submodules silently degraded
* onto the baseline path — and lost `git status` as the authoritative
* diff source. `rev-parse --is-inside-work-tree` exits 0 whenever git
* itself would accept the directory, which is the semantics we want.
*/
function isGitRepo(workspacePath: string): boolean {
try {
return existsSync(resolve(workspacePath, ".git")) && statSync(resolve(workspacePath, ".git")).isDirectory();
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
cwd: workspacePath,
timeout: 2_000,
stdio: ["ignore", "ignore", "ignore"],
});
return true;
} catch {
return false;
}