Reduce startup git work for workspace snapshots

This commit is contained in:
Mohamed Boudra
2026-05-27 20:18:49 +07:00
parent dbfd42da46
commit 5d8dc800fc
13 changed files with 862 additions and 57 deletions
+220 -36
View File
@@ -723,8 +723,29 @@ export interface MergeFromBaseOptions {
export interface CheckoutContext {
paseoHome?: string;
logger?: Pick<Logger, "trace">;
facts?: CheckoutSnapshotFacts | null;
}
export type CheckoutSnapshotFacts =
| {
isGit: false;
}
| {
isGit: true;
worktreeRoot: string;
currentBranch: string | null;
remoteUrl: string | null;
paseoWorktree: PaseoWorktreeForCwd;
storedBaseRef: string | null;
resolvedBaseRef: string | null;
mainRepoRoot: string | null;
comparisonBaseRef: string | null;
branchRemoteName: string | null;
branchMergeRef: string | null;
trackedOriginBranch: string | null;
pullRequestLookupTarget: PullRequestStatusLookupTarget | null;
};
function isGitError(error: unknown): boolean {
if (!(error instanceof Error)) {
return false;
@@ -915,6 +936,7 @@ type PaseoWorktreeForCwd =
async function getPaseoWorktreeForCwd(
cwd: string,
context?: CheckoutContext,
knownWorktreeRoot?: string | null,
): Promise<PaseoWorktreeForCwd> {
// Fast-path reject: non-worktree paths do not need expensive ownership checks.
if (!/[\\/]worktrees[\\/]/.test(cwd)) {
@@ -928,7 +950,7 @@ async function getPaseoWorktreeForCwd(
return {
isPaseoOwnedWorktree: true,
worktreeRoot: (await getWorktreeRoot(cwd)) ?? cwd,
worktreeRoot: knownWorktreeRoot ?? (await getWorktreeRoot(cwd)) ?? cwd,
};
}
@@ -940,6 +962,9 @@ async function getStoredBaseRefForCwd(
cwd: string,
context?: CheckoutContext,
): Promise<string | null> {
if (context?.facts?.isGit) {
return context.facts.storedBaseRef;
}
const paseoWorktree = await getPaseoWorktreeForCwd(cwd, context);
if (!paseoWorktree.isPaseoOwnedWorktree) {
return null;
@@ -952,6 +977,9 @@ async function getResolvedBaseRefForCwd(
cwd: string,
context?: CheckoutContext,
): Promise<string | null> {
if (context?.facts?.isGit) {
return context.facts.resolvedBaseRef;
}
const { resolvedBaseRef } = await resolveBaseRefForCwd(cwd, context);
return resolvedBaseRef;
}
@@ -965,6 +993,12 @@ async function resolveBaseRefForCwd(
cwd: string,
context?: CheckoutContext,
): Promise<BaseRefResolution> {
if (context?.facts?.isGit) {
return {
storedBaseRef: context.facts.storedBaseRef,
resolvedBaseRef: context.facts.resolvedBaseRef,
};
}
const storedBaseRef = await getStoredBaseRefForCwd(cwd, context);
return {
storedBaseRef,
@@ -1029,7 +1063,11 @@ function parseBranchMergeHeadRef(mergeRef: string | null): string | null {
async function resolvePullRequestStatusLookupTarget(
cwd: string,
currentBranch: string,
context?: CheckoutContext,
): Promise<PullRequestStatusLookupTarget> {
if (context?.facts?.isGit && context.facts.pullRequestLookupTarget) {
return context.facts.pullRequestLookupTarget;
}
const remoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.remote`);
if (!remoteName?.startsWith("paseo-pr-")) {
return { headRef: currentBranch };
@@ -1251,7 +1289,13 @@ async function getAheadBehind(
if (!normalizedBaseRef || !currentBranch || normalizedBaseRef === currentBranch) {
return null;
}
const comparisonBaseRef = await resolveBestComparisonBaseRef(cwd, baseRef, context);
const comparisonBaseRef =
context?.facts?.isGit && context.facts.resolvedBaseRef === baseRef
? context.facts.comparisonBaseRef
: await resolveBestComparisonBaseRef(cwd, baseRef, context);
if (!comparisonBaseRef) {
return null;
}
const { stdout } = await runGitCommand(
["rev-list", "--left-right", "--count", `${comparisonBaseRef}...${currentBranch}`],
{ cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger },
@@ -1309,6 +1353,9 @@ async function getTrackedOriginBranch(
currentBranch: string,
context?: CheckoutContext,
): Promise<string | null> {
if (context?.facts?.isGit && context.facts.currentBranch === currentBranch) {
return context.facts.trackedOriginBranch;
}
const remoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.remote`, context);
if (remoteName !== "origin") {
return null;
@@ -1358,7 +1405,7 @@ async function inspectCheckoutContext(
const [currentBranch, remoteUrl, paseoWorktree] = await Promise.all([
getCurrentBranch(cwd),
getOriginRemoteUrl(cwd),
getPaseoWorktreeForCwd(cwd, context),
getPaseoWorktreeForCwd(cwd, context, root),
]);
return {
@@ -1375,6 +1422,108 @@ async function inspectCheckoutContext(
}
}
function buildPullRequestLookupTargetFromBranchConfig(input: {
currentBranch: string;
branchRemoteName: string | null;
branchMergeRef: string | null;
branchRemoteUrl: string | null;
}): PullRequestStatusLookupTarget {
if (!input.branchRemoteName?.startsWith("paseo-pr-")) {
return { headRef: input.currentBranch };
}
const trackedHeadRef = parseBranchMergeHeadRef(input.branchMergeRef);
if (!trackedHeadRef) {
return { headRef: input.currentBranch };
}
const remoteRepo = input.branchRemoteUrl
? parseGitHubRepoFromRemote(input.branchRemoteUrl)
: null;
const headRepositoryOwner = remoteRepo?.split("/")[0];
return {
headRef: trackedHeadRef,
...(headRepositoryOwner ? { headRepositoryOwner } : {}),
};
}
export async function getCheckoutSnapshotFacts(
cwd: string,
context?: CheckoutContext,
): Promise<CheckoutSnapshotFacts> {
if (context?.facts) {
return context.facts;
}
const inspected = await inspectCheckoutContext(cwd, context);
if (!inspected) {
return { isGit: false };
}
const storedBaseRef = inspected.paseoWorktree.isPaseoOwnedWorktree
? readPaseoWorktreeBaseRef(inspected.paseoWorktree.worktreeRoot)
: null;
const resolvedBaseRef = storedBaseRef ?? (await resolveBaseRef(cwd));
const mainRepoRoot = await getMainRepoRoot(cwd).catch(() => null);
let comparisonBaseRef: string | null = null;
if (
resolvedBaseRef &&
inspected.currentBranch &&
normalizeLocalBranchRefName(resolvedBaseRef) !== inspected.currentBranch
) {
comparisonBaseRef = await resolveBestComparisonBaseRef(cwd, resolvedBaseRef, context).catch(
() => null,
);
}
let branchRemoteName: string | null = null;
let branchMergeRef: string | null = null;
let branchRemoteUrl: string | null = null;
if (inspected.remoteUrl && inspected.currentBranch) {
branchRemoteName = await getGitConfigValue(
cwd,
`branch.${inspected.currentBranch}.remote`,
context,
);
if (branchRemoteName) {
branchMergeRef = await getGitConfigValue(
cwd,
`branch.${inspected.currentBranch}.merge`,
context,
);
if (branchRemoteName.startsWith("paseo-pr-")) {
branchRemoteUrl = await getGitConfigValue(cwd, `remote.${branchRemoteName}.url`, context);
}
}
}
const trackedOriginBranch =
branchRemoteName === "origin" ? parseBranchMergeHeadRef(branchMergeRef) : null;
const pullRequestLookupTarget = inspected.currentBranch
? buildPullRequestLookupTargetFromBranchConfig({
currentBranch: inspected.currentBranch,
branchRemoteName,
branchMergeRef,
branchRemoteUrl,
})
: null;
return {
isGit: true,
worktreeRoot: inspected.worktreeRoot,
currentBranch: inspected.currentBranch,
remoteUrl: inspected.remoteUrl,
paseoWorktree: inspected.paseoWorktree,
storedBaseRef,
resolvedBaseRef,
mainRepoRoot,
comparisonBaseRef,
branchRemoteName,
branchMergeRef,
trackedOriginBranch,
pullRequestLookupTarget,
};
}
const PER_FILE_DIFF_MAX_BYTES = 1024 * 1024; // 1MB
const TOTAL_DIFF_MAX_BYTES = 2 * 1024 * 1024; // 2MB
const UNTRACKED_BINARY_SNIFF_BYTES = 16 * 1024;
@@ -1489,28 +1638,29 @@ export async function getCheckoutStatus(
cwd: string,
context?: CheckoutContext,
): Promise<CheckoutStatusResult> {
const inspected = await inspectCheckoutContext(cwd, context);
if (!inspected) {
const facts = await getCheckoutSnapshotFacts(cwd, context);
if (!facts.isGit) {
return { isGit: false };
}
const worktreeRoot = inspected.worktreeRoot;
const currentBranch = inspected.currentBranch;
const remoteUrl = inspected.remoteUrl;
const paseoWorktree = inspected.paseoWorktree;
const worktreeRoot = facts.worktreeRoot;
const currentBranch = facts.currentBranch;
const remoteUrl = facts.remoteUrl;
const paseoWorktree = facts.paseoWorktree;
const isDirty = await isWorkingTreeDirty(cwd, context);
const hasRemote = remoteUrl !== null;
const { resolvedBaseRef: baseRef } = await resolveBaseRefForCwd(cwd, context);
const mainRepoRoot = await getMainRepoRoot(cwd).catch(() => null);
const baseRef = facts.resolvedBaseRef;
const mainRepoRoot = facts.mainRepoRoot;
const factsContext = { ...context, facts };
const [aheadBehind, aheadOfOrigin, behindOfOrigin] = await Promise.all([
baseRef && currentBranch
? getAheadBehind(cwd, baseRef, currentBranch, context)
? getAheadBehind(cwd, baseRef, currentBranch, factsContext)
: Promise.resolve(null),
hasRemote && currentBranch
? getAheadOfOrigin(cwd, currentBranch, baseRef, context)
? getAheadOfOrigin(cwd, currentBranch, baseRef, factsContext)
: Promise.resolve(null),
hasRemote && currentBranch
? getBehindOfOrigin(cwd, currentBranch, context)
? getBehindOfOrigin(cwd, currentBranch, factsContext)
: Promise.resolve(null),
]);
@@ -1616,30 +1766,29 @@ async function getCheckoutShortstatUncached(
cwd: string,
context?: CheckoutContext,
): Promise<CheckoutShortstat | null> {
try {
await requireGitRepo(cwd);
} catch {
if (context?.facts?.isGit === false) {
return null;
}
const localBaseRef = await getResolvedBaseRefForCwd(cwd, context);
const currentBranch = await getCurrentBranch(cwd);
let comparisonRef: string;
if (currentBranch && localBaseRef && currentBranch !== localBaseRef) {
if (!context?.facts?.isGit) {
try {
comparisonRef = await resolveBestComparisonBaseRef(cwd, localBaseRef);
await requireGitRepo(cwd);
} catch {
return null;
}
} else if (currentBranch) {
const hasOrigin = await doesGitRefExist(cwd, `refs/remotes/origin/${currentBranch}`);
if (!hasOrigin) {
return null;
}
comparisonRef = `origin/${currentBranch}`;
} else {
}
const facts = context?.facts;
const localBaseRef = facts?.isGit
? facts.resolvedBaseRef
: await getResolvedBaseRefForCwd(cwd, context);
const currentBranch = facts?.isGit ? facts.currentBranch : await getCurrentBranch(cwd);
const comparisonRef = await resolveShortstatComparisonRef({
cwd,
currentBranch,
localBaseRef,
facts,
});
if (!comparisonRef) {
return null;
}
@@ -1675,6 +1824,31 @@ async function getCheckoutShortstatUncached(
}
}
async function resolveShortstatComparisonRef(input: {
cwd: string;
currentBranch: string | null;
localBaseRef: string | null;
facts?: CheckoutSnapshotFacts | null;
}): Promise<string | null> {
const { cwd, currentBranch, localBaseRef, facts } = input;
if (!currentBranch) {
return null;
}
if (localBaseRef && currentBranch !== localBaseRef) {
try {
return facts?.isGit && facts.resolvedBaseRef === localBaseRef && facts.comparisonBaseRef
? facts.comparisonBaseRef
: await resolveBestComparisonBaseRef(cwd, localBaseRef);
} catch {
return null;
}
}
const hasOrigin = await doesGitRefExist(cwd, `refs/remotes/origin/${currentBranch}`);
return hasOrigin ? `origin/${currentBranch}` : null;
}
function getOrLoadCheckoutShortstat(
cwd: string,
context?: CheckoutContext,
@@ -2460,6 +2634,7 @@ export async function getPullRequestStatus(
cwd: string,
github: GitHubService = createGitHubService(),
options?: CheckoutReadCacheOptions,
context?: CheckoutContext,
): Promise<PullRequestStatusResult> {
const cacheKey = getPullRequestStatusCacheKey(cwd);
if (!options?.force) {
@@ -2474,7 +2649,7 @@ export async function getPullRequestStatus(
}
}
const lookup = getPullRequestStatusUncached(cwd, github, options)
const lookup = getPullRequestStatusUncached(cwd, github, options, context)
.then((status) => {
pullRequestStatusCache.set(cacheKey, status);
rememberPullRequestStatus(cacheKey, status);
@@ -2501,9 +2676,18 @@ async function getPullRequestStatusUncached(
cwd: string,
github: GitHubService,
options?: CheckoutReadCacheOptions,
context?: CheckoutContext,
): Promise<PullRequestStatusResult> {
await requireGitRepo(cwd);
const head = await getCurrentBranch(cwd);
if (context?.facts?.isGit === false) {
return {
status: null,
githubFeaturesEnabled: false,
};
}
if (!context?.facts?.isGit) {
await requireGitRepo(cwd);
}
const head = context?.facts?.isGit ? context.facts.currentBranch : await getCurrentBranch(cwd);
if (!head) {
return {
status: null,
@@ -2511,7 +2695,7 @@ async function getPullRequestStatusUncached(
};
}
try {
const lookupTarget = await resolvePullRequestStatusLookupTarget(cwd, head);
const lookupTarget = await resolvePullRequestStatusLookupTarget(cwd, head, context);
let status: GitHubCurrentPullRequestStatus | null;
if (options?.force) {
const reason = options.reason;