Fix workspace diff stats for behind branches

This commit is contained in:
Mohamed Boudra
2026-04-21 22:03:24 +07:00
parent 807cce6ad9
commit 27ddfb1ea7
2 changed files with 10 additions and 50 deletions
@@ -334,7 +334,7 @@ const x = 1;
expect(divergedStatus.behindOfOrigin).toBe(1);
});
it("reports incoming additions when the base branch is behind its remote", async () => {
it("does not report incoming additions when the base branch is behind its remote", async () => {
const { cloneDir } = setupRemoteTrackingMain(repoDir, tempDir);
commitFile(cloneDir, "file.txt", "remote one\nremote two\n", "remote update");
execSync("git push", { cwd: cloneDir });
@@ -342,10 +342,10 @@ const x = 1;
const shortstat = await getCheckoutShortstat(repoDir);
expect(shortstat).toEqual({ additions: 2, deletions: 1 });
expect(shortstat).toBeNull();
});
it("reports incoming deletions when the base branch is behind its remote", async () => {
it("does not report incoming deletions when the base branch is behind its remote", async () => {
const { cloneDir } = setupRemoteTrackingMain(repoDir, tempDir);
commitFile(cloneDir, "file.txt", "", "remote deletion");
execSync("git push", { cwd: cloneDir });
@@ -353,7 +353,7 @@ const x = 1;
const shortstat = await getCheckoutShortstat(repoDir);
expect(shortstat).toEqual({ additions: 0, deletions: 1 });
expect(shortstat).toBeNull();
});
it("reports outgoing changes when the base branch is ahead of its remote", async () => {
@@ -390,7 +390,7 @@ const x = 1;
expect(shortstat).toEqual({ additions: 1, deletions: 0 });
});
it("adds working tree changes to incoming shortstat when the base branch is behind", async () => {
it("reports only working tree changes when the base branch is behind", async () => {
commitFile(repoDir, "tracked.txt", "tracked base\n", "add tracked file");
const { cloneDir } = setupRemoteTrackingMain(repoDir, tempDir);
commitFile(cloneDir, "incoming.txt", "incoming\n", "remote incoming");
@@ -400,7 +400,7 @@ const x = 1;
const shortstat = await getCheckoutShortstat(repoDir);
expect(shortstat).toEqual({ additions: 3, deletions: 1 });
expect(shortstat).toEqual({ additions: 2, deletions: 1 });
});
it("keeps feature shortstat scoped to feature changes when the base remote is ahead", async () => {
@@ -417,7 +417,7 @@ const x = 1;
expect(shortstat).toEqual({ additions: 1, deletions: 0 });
});
it("reports incoming base changes when a feature branch has no local work beyond merge-base", async () => {
it("does not report incoming base changes when a feature branch has no local work beyond merge-base", async () => {
const { cloneDir } = setupRemoteTrackingMain(repoDir, tempDir);
execSync("git checkout -b feature", { cwd: repoDir });
execSync("git checkout main", { cwd: cloneDir });
@@ -427,7 +427,7 @@ const x = 1;
const shortstat = await getCheckoutShortstat(repoDir);
expect(shortstat).toEqual({ additions: 1, deletions: 0 });
expect(shortstat).toBeNull();
});
it("reports feature shortstat ahead of the comparison merge-base", async () => {
+2 -42
View File
@@ -1358,20 +1358,6 @@ function parseCheckoutShortstat(text: string): CheckoutShortstat | null {
return { additions, deletions };
}
function combineCheckoutShortstats(
first: CheckoutShortstat | null,
second: CheckoutShortstat | null,
): CheckoutShortstat | null {
const additions = (first?.additions ?? 0) + (second?.additions ?? 0);
const deletions = (first?.deletions ?? 0) + (second?.deletions ?? 0);
if (additions === 0 && deletions === 0) {
return null;
}
return { additions, deletions };
}
async function getCheckoutShortstatUncached(
cwd: string,
context?: CheckoutContext,
@@ -1414,37 +1400,11 @@ async function getCheckoutShortstatUncached(
return null;
}
const { stdout: aheadBehindOut } = await runGitCommand(
["rev-list", "--left-right", "--count", `HEAD...${comparisonRef}`],
{ cwd, env: READ_ONLY_GIT_ENV },
);
const [headOnlyRaw, comparisonOnlyRaw] = aheadBehindOut.trim().split(/\s+/);
const headOnly = Number.parseInt(headOnlyRaw ?? "0", 10);
const comparisonOnly = Number.parseInt(comparisonOnlyRaw ?? "0", 10);
if (Number.isNaN(headOnly) || Number.isNaN(comparisonOnly)) {
return null;
}
// Incoming uses a two-ref diff, so add the working tree diff separately.
const showIncoming = headOnly === 0 && comparisonOnly > 0;
const { stdout } = await runGitCommand(
["diff", "--shortstat", mergeBase, ...(showIncoming ? [comparisonRef] : [])],
{
cwd,
env: READ_ONLY_GIT_ENV,
},
);
const committedShortstat = parseCheckoutShortstat(stdout);
if (!showIncoming) {
return committedShortstat;
}
const { stdout: worktreeOut } = await runGitCommand(["diff", "--shortstat", "HEAD"], {
const { stdout } = await runGitCommand(["diff", "--shortstat", mergeBase], {
cwd,
env: READ_ONLY_GIT_ENV,
});
return combineCheckoutShortstats(committedShortstat, parseCheckoutShortstat(worktreeOut));
return parseCheckoutShortstat(stdout);
} catch {
return null;
}