mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
fix(server): name both refs in the base ref mismatch error (#2161)
The base ref mismatch error printed the same value on both sides, so it always read "expected master, got master". All four throw sites computed `baseRef = compare.baseRef ?? resolvedBaseRef`, but the guard only fires when the caller passed a ref, so `baseRef` and the "got" value were the same string by construction. The value that actually differs -- the stored `baseRefName` from the worktree metadata -- was never shown, which left the error undiagnosable from the UI alone. Build the message in one place and have the four guards throw it, naming the refs `stored` and `requested`. The wording deliberately avoids "expected": a caller's ref can be stale, but the stored ref can equally be the wrong one, so the message states both facts and leaves the diagnosis open. The guards stay where they are. Only the message moves, so the condition that fires each throw is still visible at the call site, and both refs are narrowed to plain strings by the time the message is built. Throw conditions are unchanged; only the message text differs. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3002,6 +3002,20 @@ const x = 1;
|
|||||||
expect(baseDiff.diff).not.toContain("file.txt");
|
expect(baseDiff.diff).not.toContain("file.txt");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("names both refs when a requested base ref does not match the stored one", async () => {
|
||||||
|
const worktree = await createLegacyWorktreeForTest({
|
||||||
|
branchName: "mismatch-feature",
|
||||||
|
cwd: repoDir,
|
||||||
|
baseBranch: "main",
|
||||||
|
worktreeSlug: "mismatch-feature",
|
||||||
|
paseoHome,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
getCheckoutDiff(worktree.worktreePath, { mode: "base", baseRef: "other" }, { paseoHome }),
|
||||||
|
).rejects.toThrow("Base ref mismatch: stored main, requested other");
|
||||||
|
});
|
||||||
|
|
||||||
it("excludes dirty working tree changes from Paseo worktree base diffs", async () => {
|
it("excludes dirty working tree changes from Paseo worktree base diffs", async () => {
|
||||||
const worktree = await createLegacyWorktreeForTest({
|
const worktree = await createLegacyWorktreeForTest({
|
||||||
branchName: "feature",
|
branchName: "feature",
|
||||||
|
|||||||
@@ -1134,6 +1134,12 @@ async function resolveBaseRefForCwd(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Names both refs rather than labelling either one correct: a caller's ref can be stale, but the
|
||||||
|
// stored ref can equally be wrong, so the message states the two facts and leaves the diagnosis open.
|
||||||
|
function baseRefMismatchError(refs: { stored: string; requested: string }): Error {
|
||||||
|
return new Error(`Base ref mismatch: stored ${refs.stored}, requested ${refs.requested}`);
|
||||||
|
}
|
||||||
|
|
||||||
async function isWorkingTreeDirty(cwd: string, context?: CheckoutContext): Promise<boolean> {
|
async function isWorkingTreeDirty(cwd: string, context?: CheckoutContext): Promise<boolean> {
|
||||||
const { stdout } = await runGitCommand(["status", "--porcelain"], {
|
const { stdout } = await runGitCommand(["status", "--porcelain"], {
|
||||||
cwd,
|
cwd,
|
||||||
@@ -2795,7 +2801,7 @@ async function resolveCheckoutDiffRefs(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (storedBaseRef && compare.baseRef && compare.baseRef !== storedBaseRef) {
|
if (storedBaseRef && compare.baseRef && compare.baseRef !== storedBaseRef) {
|
||||||
throw new Error(`Base ref mismatch: expected ${baseRef}, got ${compare.baseRef}`);
|
throw baseRefMismatchError({ stored: storedBaseRef, requested: compare.baseRef });
|
||||||
}
|
}
|
||||||
const bestBaseRef = await resolveBestComparisonBaseRef(cwd, baseRef);
|
const bestBaseRef = await resolveBestComparisonBaseRef(cwd, baseRef);
|
||||||
return {
|
return {
|
||||||
@@ -3009,7 +3015,7 @@ export async function mergeToBase(
|
|||||||
throw new Error("Unable to determine base branch for merge");
|
throw new Error("Unable to determine base branch for merge");
|
||||||
}
|
}
|
||||||
if (storedBaseRef && options.baseRef && options.baseRef !== storedBaseRef) {
|
if (storedBaseRef && options.baseRef && options.baseRef !== storedBaseRef) {
|
||||||
throw new Error(`Base ref mismatch: expected ${baseRef}, got ${options.baseRef}`);
|
throw baseRefMismatchError({ stored: storedBaseRef, requested: options.baseRef });
|
||||||
}
|
}
|
||||||
if (!currentBranch) {
|
if (!currentBranch) {
|
||||||
throw new Error("Unable to determine current branch for merge");
|
throw new Error("Unable to determine current branch for merge");
|
||||||
@@ -3085,7 +3091,7 @@ export async function mergeFromBase(
|
|||||||
throw new Error("Unable to determine base branch for merge");
|
throw new Error("Unable to determine base branch for merge");
|
||||||
}
|
}
|
||||||
if (storedBaseRef && options.baseRef && options.baseRef !== storedBaseRef) {
|
if (storedBaseRef && options.baseRef && options.baseRef !== storedBaseRef) {
|
||||||
throw new Error(`Base ref mismatch: expected ${baseRef}, got ${options.baseRef}`);
|
throw baseRefMismatchError({ stored: storedBaseRef, requested: options.baseRef });
|
||||||
}
|
}
|
||||||
|
|
||||||
const requireCleanTarget = options.requireCleanTarget ?? true;
|
const requireCleanTarget = options.requireCleanTarget ?? true;
|
||||||
@@ -3423,7 +3429,7 @@ export async function createPullRequest(
|
|||||||
}
|
}
|
||||||
const normalizedBase = normalizeLocalBranchRefName(base);
|
const normalizedBase = normalizeLocalBranchRefName(base);
|
||||||
if (storedBaseRef && options.base && options.base !== storedBaseRef) {
|
if (storedBaseRef && options.base && options.base !== storedBaseRef) {
|
||||||
throw new Error(`Base ref mismatch: expected ${base}, got ${options.base}`);
|
throw baseRefMismatchError({ stored: storedBaseRef, requested: options.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
// The push deliberately happens before the adapter resolves the target
|
// The push deliberately happens before the adapter resolves the target
|
||||||
|
|||||||
Reference in New Issue
Block a user