diff --git a/apps/server/src/vcs/GitVcsDriverCore.ts b/apps/server/src/vcs/GitVcsDriverCore.ts index 0dd73af687f9..4ce3f7e07866 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.ts @@ -860,6 +860,9 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* cwd: commandInput.cwd, env: { ...process.env, + // Status polling runs beside the user's own git commands; without this, + // `git status` takes index.lock to save its refreshed index. + GIT_OPTIONAL_LOCKS: "0", ...input.env, ...trace2Monitor.env, }, @@ -1771,10 +1774,12 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* const statusCacheKey = repositoryPaths?.gitCommonDir; const [numstatStdout, defaultBranch, hasPrimaryRemote] = yield* Effect.all( [ + // Plumbing, because porcelain `git diff` rewrites the index even with + // GIT_OPTIONAL_LOCKS=0. -M keeps porcelain's rename detection. executeGitWithStableDiagnostics( "GitVcsDriver.statusDetails.numstat", cwd, - ["diff", "HEAD", "--numstat", "--"], + ["diff-index", "-M", "--numstat", "HEAD", "--"], { allowNonZeroExit: true }, ).pipe( Effect.flatMap((result) => { @@ -1783,7 +1788,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* return Effect.map( Effect.all([ runGitStdout("GitVcsDriver.statusDetails.numstat.unborn", cwd, [ - "diff", + "diff-files", "--numstat", ]), runGitStdout("GitVcsDriver.statusDetails.numstat.unborn.staged", cwd, [ @@ -1816,9 +1821,9 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* ...gitCommandContext({ operation: "GitVcsDriver.statusDetails.numstat", cwd, - args: ["diff", "HEAD", "--numstat", "--"], + args: ["diff-index", "-M", "--numstat", "HEAD", "--"], }), - detail: "git diff HEAD --numstat failed.", + detail: "git diff-index HEAD --numstat failed.", exitCode: result.exitCode, stdoutLength: result.stdout.length, stderrLength: result.stderr.length,