authorgravatar for 73941998+UtkarshUsername@users.noreply.github.comUtkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> 2026-07-29 21:54:11+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-29 18:24:11+02:00
logfaea70aebae41f1257140c6722f1d78f12f5eb74
treeddd51c42de41034e7908e0e863386936ee4caac2
parentd19039aeef6942e6eb204856c43b5354c0333e2d
signature Signed by PGP key B5690EEEBB952194

perf(server): merge separate staged/unstaged numstat calls into single diff HEAD --numstat (#4843)


2 files changed, 122 insertions(+), 28 deletions(-)

apps/server/src/vcs/GitVcsDriverCore.test.ts+46
...@@ -997,6 +997,52 @@ it.layer(TestLayer)("GitVcsDriver core integration", (it) => {...@@ -997,6 +997,52 @@ it.layer(TestLayer)("GitVcsDriver core integration", (it) => {
997 assert.equal(status.aheadOfDefaultCount, 1);997 assert.equal(status.aheadOfDefaultCount, 1);
998 }),998 }),
999 );999 );
1000
1001 it.effect("reports combined staged and unstaged edits to the same file", () =>
1002 Effect.gen(function* () {
1003 const cwd = yield* makeTmpDir();
1004 yield* initRepoWithCommit(cwd);
1005 yield* writeTextFile(cwd, "feature.ts", "// line one\n");
1006 yield* git(cwd, ["add", "feature.ts"]);
1007 yield* git(cwd, ["commit", "-m", "add feature"]);
1008 yield* writeTextFile(cwd, "feature.ts", "// line one\n// line two\n");
1009 yield* git(cwd, ["add", "feature.ts"]);
1010 yield* writeTextFile(cwd, "feature.ts", "// line one\n// line two\n// line three\n");
1011
1012 const status = yield* (yield* GitVcsDriver.GitVcsDriver).statusDetails(cwd);
1013
1014 assert.equal(status.isRepo, true);
1015 assert.equal(status.hasWorkingTreeChanges, true);
1016 const file = status.workingTree.files.find((f) => f.path === "feature.ts");
1017 assert.ok(file);
1018 // HEAD has 1 line. Staged has 2 lines (+1). Unstaged has 3 lines (+2 from HEAD).
1019 // Combined net from HEAD: +2 insertions.
1020 assert.equal(file.insertions, 2);
1021 assert.equal(file.deletions, 0);
1022 }),
1023 );
1024
1025 it.effect("reports staged file counts on unborn HEAD without failing", () =>
1026 Effect.gen(function* () {
1027 const cwd = yield* makeTmpDir();
1028 const driver = yield* GitVcsDriver.GitVcsDriver;
1029 yield* driver.initRepo({ cwd });
1030 yield* git(cwd, ["config", "user.email", "test@test.com"]);
1031 yield* git(cwd, ["config", "user.name", "Test"]);
1032 yield* writeTextFile(cwd, "initial.ts", "// first file\n");
1033 yield* git(cwd, ["add", "initial.ts"]);
1034
1035 const status = yield* driver.statusDetails(cwd);
1036
1037 assert.equal(status.isRepo, true);
1038 assert.equal(status.workingTree.files.length, 1);
1039 const file = status.workingTree.files[0];
1040 if (file) {
1041 assert.equal(file.path, "initial.ts");
1042 assert.equal(file.insertions, 1);
1043 }
1044 }),
1045 );
1000 });1046 });
10011047
1002 describe("refName operations", () => {1048 describe("refName operations", () => {
apps/server/src/vcs/GitVcsDriverCore.ts+76-28
...@@ -415,6 +415,12 @@ function isMissingGitCwdError(error: GitCommandError): boolean {...@@ -415,6 +415,12 @@ function isMissingGitCwdError(error: GitCommandError): boolean {
415function isNonRepositoryGitStderr(stderr: string): boolean {415function isNonRepositoryGitStderr(stderr: string): boolean {
416 return stderr.toLowerCase().includes("not a git repository");416 return stderr.toLowerCase().includes("not a git repository");
417}417}
418function isUnbornHeadStderr(stderr: string): boolean {
419 return (
420 stderr.toLowerCase().includes("unknown revision") &&
421 stderr.toLowerCase().includes("path not in the working tree")
422 );
423}
418424
419interface Trace2Monitor {425interface Trace2Monitor {
420 readonly env: NodeJS.ProcessEnv;426 readonly env: NodeJS.ProcessEnv;
...@@ -1511,27 +1517,73 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*...@@ -1511,27 +1517,73 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
1511 });1517 });
1512 }1518 }
15131519
1514 const [unstagedNumstatStdout, stagedNumstatStdout, defaultRefResult, hasPrimaryRemote] =1520 const [numstatStdout, defaultRefResult, hasPrimaryRemote] = yield* Effect.all(
1515 yield* Effect.all(1521 [
1516 [1522 executeGitWithStableDiagnostics(
1517 runGitStdout("GitVcsDriver.statusDetails.unstagedNumstat", cwd, ["diff", "--numstat"]),1523 "GitVcsDriver.statusDetails.numstat",
1518 runGitStdout("GitVcsDriver.statusDetails.stagedNumstat", cwd, [1524 cwd,
1519 "diff",1525 ["diff", "HEAD", "--numstat"],
1520 "--cached",1526 { allowNonZeroExit: true },
1521 "--numstat",1527 ).pipe(
1522 ]),1528 Effect.flatMap((result) => {
1523 executeGit(1529 if (result.exitCode === 0) return Effect.succeed(result.stdout);
1524 "GitVcsDriver.statusDetails.defaultRef",1530 if (isUnbornHeadStderr(result.stderr)) {
1525 cwd,1531 return Effect.map(
1526 ["symbolic-ref", "refs/remotes/origin/HEAD"],1532 Effect.all([
1527 {1533 runGitStdout("GitVcsDriver.statusDetails.numstat.unborn", cwd, [
1528 allowNonZeroExit: true,1534 "diff",
1529 },1535 "--numstat",
1530 ),1536 ]),
1531 originRemoteExists(cwd).pipe(Effect.orElseSucceed(() => false)),1537 runGitStdout("GitVcsDriver.statusDetails.numstat.unborn.staged", cwd, [
1532 ],1538 "diff",
1533 { concurrency: "unbounded" },1539 "--cached",
1534 );1540 "--numstat",
1541 ]),
1542 ]),
1543 ([unstagedStdout, stagedStdout]) => {
1544 const staged = parseNumstatEntries(stagedStdout);
1545 const unstaged = parseNumstatEntries(unstagedStdout);
1546 const map = new Map<string, { insertions: number; deletions: number }>();
1547 for (const entry of [...staged, ...unstaged]) {
1548 const existing = map.get(entry.path) ?? {
1549 insertions: 0,
1550 deletions: 0,
1551 };
1552 existing.insertions += entry.insertions;
1553 existing.deletions += entry.deletions;
1554 map.set(entry.path, existing);
1555 }
1556 return Array.from(map.entries())
1557 .map(([p, s]) => `${s.insertions}\t${s.deletions}\t${p}`)
1558 .join("\n");
1559 },
1560 );
1561 }
1562 return Effect.fail(
1563 new GitCommandError({
1564 ...gitCommandContext({
1565 operation: "GitVcsDriver.statusDetails.numstat",
1566 cwd,
1567 args: ["diff", "HEAD", "--numstat"],
1568 }),
1569 detail: "git diff HEAD --numstat failed.",
1570 exitCode: result.exitCode,
1571 stdoutLength: result.stdout.length,
1572 stderrLength: result.stderr.length,
1573 }),
1574 );
1575 }),
1576 ),
1577 executeGit(
1578 "GitVcsDriver.statusDetails.defaultRef",
1579 cwd,
1580 ["symbolic-ref", "refs/remotes/origin/HEAD"],
1581 { allowNonZeroExit: true },
1582 ),
1583 originRemoteExists(cwd).pipe(Effect.orElseSucceed(() => false)),
1584 ],
1585 { concurrency: "unbounded" },
1586 );
1535 const statusStdout = statusResult.stdout;1587 const statusStdout = statusResult.stdout;
1536 const defaultBranch =1588 const defaultBranch =
1537 defaultRefResult.exitCode === 01589 defaultRefResult.exitCode === 0
...@@ -1592,14 +1644,10 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*...@@ -1592,14 +1644,10 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
1592 : yield* computeAheadCountAgainstBase(cwd, refName).pipe(Effect.orElseSucceed(() => 0));1644 : yield* computeAheadCountAgainstBase(cwd, refName).pipe(Effect.orElseSucceed(() => 0));
1593 }1645 }
15941646
1595 const stagedEntries = parseNumstatEntries(stagedNumstatStdout);1647 const numstatEntries = parseNumstatEntries(numstatStdout);
1596 const unstagedEntries = parseNumstatEntries(unstagedNumstatStdout);
1597 const fileStatMap = new Map<string, { insertions: number; deletions: number }>();1648 const fileStatMap = new Map<string, { insertions: number; deletions: number }>();
1598 for (const entry of [...stagedEntries, ...unstagedEntries]) {1649 for (const entry of numstatEntries) {
1599 const existing = fileStatMap.get(entry.path) ?? { insertions: 0, deletions: 0 };1650 fileStatMap.set(entry.path, { insertions: entry.insertions, deletions: entry.deletions });
1600 existing.insertions += entry.insertions;
1601 existing.deletions += entry.deletions;
1602 fileStatMap.set(entry.path, existing);
1603 }1651 }
16041652
1605 let insertions = 0;1653 let insertions = 0;