Reuse git facts for workspace observation
This commit is contained in:
@@ -70,14 +70,17 @@ The frozen home used for the comparison contained 22 workspaces.
|
|||||||
|
|
||||||
### Before/After
|
### Before/After
|
||||||
|
|
||||||
| run | code shape | client shape | git commands | failures | elapsed |
|
| run | code shape | client shape | git commands | failures | elapsed |
|
||||||
| ----------- | ------------- | ----------------------------------------- | -----------: | -------: | ------: |
|
| ----------- | -------------------------- | ----------------------------------------- | -----------: | -------: | ------: |
|
||||||
| baseline | before change | legacy sidebar PR fanout | 529 | 20 | 39039ms |
|
| baseline | before change | legacy sidebar PR fanout | 529 | 20 | 39039ms |
|
||||||
| split check | after change | legacy sidebar PR fanout | 375 | 15 | 39039ms |
|
| split check | after change | legacy sidebar PR fanout | 375 | 15 | 39039ms |
|
||||||
| after | after change | snapshot-only sidebar, no PR badge fanout | 372 | 15 | 31273ms |
|
| after | after change | snapshot-only sidebar, no PR badge fanout | 372 | 15 | 31273ms |
|
||||||
|
| after 2 | after service fact sharing | snapshot-only sidebar, no PR badge fanout | 308 | 15 | 31334ms |
|
||||||
|
|
||||||
The server-side fact reuse accounts for nearly all measured git command reduction: `529 -> 375` (`-154`, `-29.1%`) even when the old PR fanout is still forced. Removing the sidebar fanout removes the ad hoc request path, but in this run it only changed command count by `3` because the refreshed workspace snapshots already carried the PR data by the time the fanout ran.
|
The server-side fact reuse accounts for nearly all measured git command reduction: `529 -> 375` (`-154`, `-29.1%`) even when the old PR fanout is still forced. Removing the sidebar fanout removes the ad hoc request path, but in this run it only changed command count by `3` because the refreshed workspace snapshots already carried the PR data by the time the fanout ran.
|
||||||
|
|
||||||
|
The second pass shares checkout facts between workspace observation setup and snapshot refresh. That removes another `64` git commands from the same frozen-home run: `372 -> 308` (`-17.2%` from the previous after, `-41.8%` from baseline).
|
||||||
|
|
||||||
### Baseline: before change + legacy PR fanout
|
### Baseline: before change + legacy PR fanout
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -148,6 +151,41 @@ The server-side fact reuse accounts for nearly all measured git command reductio
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### After 2: shared service-level facts
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scenario": "snapshotOnly",
|
||||||
|
"workspaceCount": 22,
|
||||||
|
"elapsedMs": 31334,
|
||||||
|
"git": {
|
||||||
|
"total": 308,
|
||||||
|
"failed": 15,
|
||||||
|
"maxConcurrent": 8,
|
||||||
|
"byCommand": [
|
||||||
|
{ "key": "show-ref --verify --quiet refs/heads/main", "count": 31 },
|
||||||
|
{ "key": "rev-parse --git-common-dir", "count": 26 },
|
||||||
|
{ "key": "show-ref --verify --quiet refs/remotes/origin/main", "count": 22 },
|
||||||
|
{ "key": "ls-files --others --exclude-standard", "count": 18 },
|
||||||
|
{ "key": "status --porcelain", "count": 18 },
|
||||||
|
{ "key": "merge-base HEAD origin/main", "count": 17 },
|
||||||
|
{ "key": "config --get remote.origin.url", "count": 13 },
|
||||||
|
{ "key": "rev-parse --abbrev-ref HEAD", "count": 13 },
|
||||||
|
{ "key": "rev-parse --absolute-git-dir", "count": 13 },
|
||||||
|
{ "key": "rev-parse --show-toplevel", "count": 13 },
|
||||||
|
{ "key": "symbolic-ref --quiet refs/remotes/origin/HEAD", "count": 13 },
|
||||||
|
{ "key": "fetch origin --prune", "count": 5 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"process": {
|
||||||
|
"cpuUserMs": 1817,
|
||||||
|
"cpuSystemMs": 1869,
|
||||||
|
"rssDeltaMb": 16.7,
|
||||||
|
"heapUsedDeltaMb": 10.4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Snapshot Equivalence Guard
|
## Snapshot Equivalence Guard
|
||||||
|
|
||||||
Added a focused utility test proving that status, shortstat, and PR status return the same data when run from shared snapshot facts. The same test records git calls and asserts the facts-backed path does not re-run:
|
Added a focused utility test proving that status, shortstat, and PR status return the same data when run from shared snapshot facts. The same test records git calls and asserts the facts-backed path does not re-run:
|
||||||
@@ -165,9 +203,9 @@ This pass reshaped the data flow and removed the sidebar PR badge special path.
|
|||||||
|
|
||||||
The benchmark still shows repeated per-workspace reads that are candidates for the next pass:
|
The benchmark still shows repeated per-workspace reads that are candidates for the next pass:
|
||||||
|
|
||||||
- origin URL lookup repeats across snapshot facts and GitHub remote resolution paths.
|
|
||||||
- base ref existence checks still repeat as `show-ref` probes.
|
- base ref existence checks still repeat as `show-ref` probes.
|
||||||
- repo/worktree identity still requires one root/current-branch rev-parse per workspace.
|
- default branch resolution still repeats `symbolic-ref refs/remotes/origin/HEAD`.
|
||||||
|
- repo common-dir lookup is lower, but still above the apparent git workspace count.
|
||||||
- shortstat still runs its own merge-base/diff/untracked scan per workspace.
|
- shortstat still runs its own merge-base/diff/untracked scan per workspace.
|
||||||
|
|
||||||
The important invariant now is clearer: sidebar-visible git data should flow from `WorkspaceGitService` snapshots, and snapshot builders should receive reusable git facts through `CheckoutContext`.
|
The important invariant now is clearer: sidebar-visible git data should flow from `WorkspaceGitService` snapshots, and snapshot builders should receive reusable git facts through `CheckoutContext`.
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ function createCheckoutSnapshotFacts(cwd: string): CheckoutSnapshotFacts {
|
|||||||
worktreeRoot: cwd,
|
worktreeRoot: cwd,
|
||||||
currentBranch: "main",
|
currentBranch: "main",
|
||||||
remoteUrl: "https://github.com/acme/repo.git",
|
remoteUrl: "https://github.com/acme/repo.git",
|
||||||
|
absoluteGitDir: join(cwd, ".git"),
|
||||||
|
gitCommonDir: join(cwd, ".git"),
|
||||||
paseoWorktree: { isPaseoOwnedWorktree: false },
|
paseoWorktree: { isPaseoOwnedWorktree: false },
|
||||||
storedBaseRef: null,
|
storedBaseRef: null,
|
||||||
resolvedBaseRef: "main",
|
resolvedBaseRef: "main",
|
||||||
@@ -427,10 +429,12 @@ describe("WorkspaceGitServiceImpl", () => {
|
|||||||
|
|
||||||
test("multiple listeners on the same workspace share one observation setup", async () => {
|
test("multiple listeners on the same workspace share one observation setup", async () => {
|
||||||
const getPullRequestStatus = vi.fn(async () => createPullRequestStatusResult());
|
const getPullRequestStatus = vi.fn(async () => createPullRequestStatusResult());
|
||||||
|
const getCheckoutSnapshotFacts = vi.fn(async (cwd: string) => createCheckoutSnapshotFacts(cwd));
|
||||||
const resolveAbsoluteGitDir = vi.fn(async () => join(REPO_CWD, ".git"));
|
const resolveAbsoluteGitDir = vi.fn(async () => join(REPO_CWD, ".git"));
|
||||||
|
|
||||||
let nowMs = Date.parse("2026-04-12T00:00:00.000Z");
|
let nowMs = Date.parse("2026-04-12T00:00:00.000Z");
|
||||||
const service = createService({
|
const service = createService({
|
||||||
|
getCheckoutSnapshotFacts,
|
||||||
getPullRequestStatus,
|
getPullRequestStatus,
|
||||||
resolveAbsoluteGitDir,
|
resolveAbsoluteGitDir,
|
||||||
now: () => new Date(nowMs),
|
now: () => new Date(nowMs),
|
||||||
@@ -441,7 +445,8 @@ describe("WorkspaceGitServiceImpl", () => {
|
|||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
expect(getPullRequestStatus).toHaveBeenCalledTimes(0);
|
expect(getPullRequestStatus).toHaveBeenCalledTimes(0);
|
||||||
expect(resolveAbsoluteGitDir).toHaveBeenCalledTimes(1);
|
expect(getCheckoutSnapshotFacts).toHaveBeenCalledTimes(1);
|
||||||
|
expect(resolveAbsoluteGitDir).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
first.unsubscribe();
|
first.unsubscribe();
|
||||||
second.unsubscribe();
|
second.unsubscribe();
|
||||||
@@ -473,7 +478,7 @@ describe("WorkspaceGitServiceImpl", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(getPullRequestStatus).toHaveBeenCalledTimes(1);
|
expect(getPullRequestStatus).toHaveBeenCalledTimes(1);
|
||||||
expect(resolveAbsoluteGitDir).toHaveBeenCalledTimes(1);
|
expect(resolveAbsoluteGitDir).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
service.dispose();
|
service.dispose();
|
||||||
@@ -482,9 +487,15 @@ describe("WorkspaceGitServiceImpl", () => {
|
|||||||
test("repo-level fetch intervals are shared for workspaces in the same repo", async () => {
|
test("repo-level fetch intervals are shared for workspaces in the same repo", async () => {
|
||||||
const runGitFetch = vi.fn(async () => {});
|
const runGitFetch = vi.fn(async () => {});
|
||||||
const hasOriginRemote = vi.fn(async () => true);
|
const hasOriginRemote = vi.fn(async () => true);
|
||||||
|
const getCheckoutSnapshotFacts = vi.fn(async (cwd: string) => ({
|
||||||
|
...createCheckoutSnapshotFacts(cwd),
|
||||||
|
gitCommonDir: join(REPO_CWD, ".git"),
|
||||||
|
absoluteGitDir: join(REPO_CWD, ".git"),
|
||||||
|
}));
|
||||||
const resolveAbsoluteGitDir = vi.fn(async () => join(REPO_CWD, ".git"));
|
const resolveAbsoluteGitDir = vi.fn(async () => join(REPO_CWD, ".git"));
|
||||||
|
|
||||||
const service = createService({
|
const service = createService({
|
||||||
|
getCheckoutSnapshotFacts,
|
||||||
resolveAbsoluteGitDir,
|
resolveAbsoluteGitDir,
|
||||||
hasOriginRemote,
|
hasOriginRemote,
|
||||||
runGitFetch,
|
runGitFetch,
|
||||||
@@ -496,11 +507,12 @@ describe("WorkspaceGitServiceImpl", () => {
|
|||||||
vi.fn(),
|
vi.fn(),
|
||||||
);
|
);
|
||||||
await vi.waitFor(() => {
|
await vi.waitFor(() => {
|
||||||
expect(resolveAbsoluteGitDir).toHaveBeenCalledTimes(2);
|
expect(getCheckoutSnapshotFacts).toHaveBeenCalledTimes(2);
|
||||||
expect(runGitFetch).toHaveBeenCalledTimes(1);
|
expect(runGitFetch).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(hasOriginRemote).toHaveBeenCalledTimes(1);
|
expect(resolveAbsoluteGitDir).toHaveBeenCalledTimes(0);
|
||||||
|
expect(hasOriginRemote).toHaveBeenCalledTimes(0);
|
||||||
expect(runGitFetch).toHaveBeenCalledTimes(1);
|
expect(runGitFetch).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
await vi.advanceTimersByTimeAsync(180_000);
|
await vi.advanceTimersByTimeAsync(180_000);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ const WORKING_TREE_WATCH_FALLBACK_REFRESH_MS = 5_000;
|
|||||||
const WORKSPACE_GIT_AUXILIARY_READ_TTL_MS = 15_000;
|
const WORKSPACE_GIT_AUXILIARY_READ_TTL_MS = 15_000;
|
||||||
// Non-forced refresh triggers share this minimum gap to absorb watcher/self-heal bursts; force bypasses it.
|
// Non-forced refresh triggers share this minimum gap to absorb watcher/self-heal bursts; force bypasses it.
|
||||||
const WORKSPACE_GIT_INTERNAL_MIN_GAP_MS = 2_000;
|
const WORKSPACE_GIT_INTERNAL_MIN_GAP_MS = 2_000;
|
||||||
|
const WORKSPACE_GIT_FACTS_REUSE_TTL_MS = 1_000;
|
||||||
const LINUX_WATCH_MAX_DIRS = 5_000;
|
const LINUX_WATCH_MAX_DIRS = 5_000;
|
||||||
const LINUX_WATCH_REFRESH_COOLDOWN_MS = 2_000;
|
const LINUX_WATCH_REFRESH_COOLDOWN_MS = 2_000;
|
||||||
const LINUX_WATCH_IGNORE_TTL_MS = 5 * 60 * 1_000;
|
const LINUX_WATCH_IGNORE_TTL_MS = 5 * 60 * 1_000;
|
||||||
@@ -271,6 +272,9 @@ interface WorkspaceGitTarget {
|
|||||||
latestGithubLoadedAtMs: number | null;
|
latestGithubLoadedAtMs: number | null;
|
||||||
latestSnapshot: WorkspaceGitRuntimeSnapshot | null;
|
latestSnapshot: WorkspaceGitRuntimeSnapshot | null;
|
||||||
latestSnapshotLoadedAtMs: number | null;
|
latestSnapshotLoadedAtMs: number | null;
|
||||||
|
latestFacts: CheckoutSnapshotFacts | null;
|
||||||
|
latestFactsLoadedAtMs: number | null;
|
||||||
|
factsPromise: Promise<CheckoutSnapshotFacts> | null;
|
||||||
latestFingerprint: string | null;
|
latestFingerprint: string | null;
|
||||||
lastShellOutAtMs: number | null;
|
lastShellOutAtMs: number | null;
|
||||||
repoGitRoot: string | null;
|
repoGitRoot: string | null;
|
||||||
@@ -787,6 +791,9 @@ export class WorkspaceGitServiceImpl implements WorkspaceGitService {
|
|||||||
latestGithubLoadedAtMs: null,
|
latestGithubLoadedAtMs: null,
|
||||||
latestSnapshot: null,
|
latestSnapshot: null,
|
||||||
latestSnapshotLoadedAtMs: null,
|
latestSnapshotLoadedAtMs: null,
|
||||||
|
latestFacts: null,
|
||||||
|
latestFactsLoadedAtMs: null,
|
||||||
|
factsPromise: null,
|
||||||
latestFingerprint: null,
|
latestFingerprint: null,
|
||||||
lastShellOutAtMs: null,
|
lastShellOutAtMs: null,
|
||||||
repoGitRoot: null,
|
repoGitRoot: null,
|
||||||
@@ -837,7 +844,8 @@ export class WorkspaceGitServiceImpl implements WorkspaceGitService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async setupWorkspaceObservation(target: WorkspaceGitTarget): Promise<void> {
|
private async setupWorkspaceObservation(target: WorkspaceGitTarget): Promise<void> {
|
||||||
const gitDir = await this.deps.resolveAbsoluteGitDir(target.cwd);
|
const facts = await this.getFactsForObservation(target);
|
||||||
|
const gitDir = facts?.isGit ? facts.absoluteGitDir : null;
|
||||||
if (!this.isActiveObservedWorkspaceTarget(target)) {
|
if (!this.isActiveObservedWorkspaceTarget(target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -846,7 +854,10 @@ export class WorkspaceGitServiceImpl implements WorkspaceGitService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const repoGitRoot = await this.resolveWorkspaceGitRefsRoot(gitDir);
|
const repoGitRoot =
|
||||||
|
facts?.isGit && facts.gitCommonDir
|
||||||
|
? facts.gitCommonDir
|
||||||
|
: await this.resolveWorkspaceGitRefsRoot(gitDir);
|
||||||
if (!this.isActiveObservedWorkspaceTarget(target)) {
|
if (!this.isActiveObservedWorkspaceTarget(target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -858,6 +869,48 @@ export class WorkspaceGitServiceImpl implements WorkspaceGitService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getFactsForObservation(
|
||||||
|
target: WorkspaceGitTarget,
|
||||||
|
): Promise<CheckoutSnapshotFacts | null> {
|
||||||
|
return this.loadCheckoutFacts(target, {
|
||||||
|
paseoHome: this.paseoHome,
|
||||||
|
logger: this.logger,
|
||||||
|
allowRecent: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadCheckoutFacts(
|
||||||
|
target: WorkspaceGitTarget,
|
||||||
|
options: CheckoutContext & { allowRecent: boolean },
|
||||||
|
): Promise<CheckoutSnapshotFacts> {
|
||||||
|
if (options.allowRecent && target.latestFacts && target.latestFactsLoadedAtMs !== null) {
|
||||||
|
const ageMs = this.deps.now().getTime() - target.latestFactsLoadedAtMs;
|
||||||
|
if (ageMs < WORKSPACE_GIT_FACTS_REUSE_TTL_MS) {
|
||||||
|
return Promise.resolve(target.latestFacts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.factsPromise) {
|
||||||
|
return target.factsPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { allowRecent: _allowRecent, ...context } = options;
|
||||||
|
const promise = this.deps
|
||||||
|
.getCheckoutSnapshotFacts(target.cwd, context)
|
||||||
|
.then((facts) => {
|
||||||
|
target.latestFacts = facts;
|
||||||
|
target.latestFactsLoadedAtMs = this.deps.now().getTime();
|
||||||
|
return facts;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (target.factsPromise === promise) {
|
||||||
|
target.factsPromise = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
target.factsPromise = promise;
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
private isActiveObservedWorkspaceTarget(target: WorkspaceGitTarget): boolean {
|
private isActiveObservedWorkspaceTarget(target: WorkspaceGitTarget): boolean {
|
||||||
return (
|
return (
|
||||||
!target.closed &&
|
!target.closed &&
|
||||||
@@ -996,7 +1049,11 @@ export class WorkspaceGitServiceImpl implements WorkspaceGitService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasOrigin = await this.deps.hasOriginRemote(workspaceTarget.cwd);
|
const facts = workspaceTarget.latestFacts;
|
||||||
|
const hasOrigin =
|
||||||
|
facts?.isGit === true
|
||||||
|
? facts.remoteUrl !== null
|
||||||
|
: await this.deps.hasOriginRemote(workspaceTarget.cwd);
|
||||||
if (!this.isActiveObservedWorkspaceTarget(workspaceTarget)) {
|
if (!this.isActiveObservedWorkspaceTarget(workspaceTarget)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1505,7 +1562,10 @@ export class WorkspaceGitServiceImpl implements WorkspaceGitService {
|
|||||||
const cwd = target.cwd;
|
const cwd = target.cwd;
|
||||||
const previousGitHubPollKey = this.getGitHubPollKey(target);
|
const previousGitHubPollKey = this.getGitHubPollKey(target);
|
||||||
const baseContext: CheckoutContext = { paseoHome: this.paseoHome, logger: this.logger };
|
const baseContext: CheckoutContext = { paseoHome: this.paseoHome, logger: this.logger };
|
||||||
const facts = await this.deps.getCheckoutSnapshotFacts(cwd, baseContext);
|
const facts = await this.loadCheckoutFacts(target, {
|
||||||
|
...baseContext,
|
||||||
|
allowRecent: !request.force,
|
||||||
|
});
|
||||||
const context: CheckoutContext = { ...baseContext, facts };
|
const context: CheckoutContext = { ...baseContext, facts };
|
||||||
const checkoutStatus = await this.deps.getCheckoutStatus(cwd, context);
|
const checkoutStatus = await this.deps.getCheckoutStatus(cwd, context);
|
||||||
if (!checkoutStatus.isGit) {
|
if (!checkoutStatus.isGit) {
|
||||||
|
|||||||
@@ -735,6 +735,8 @@ export type CheckoutSnapshotFacts =
|
|||||||
worktreeRoot: string;
|
worktreeRoot: string;
|
||||||
currentBranch: string | null;
|
currentBranch: string | null;
|
||||||
remoteUrl: string | null;
|
remoteUrl: string | null;
|
||||||
|
absoluteGitDir: string | null;
|
||||||
|
gitCommonDir: string | null;
|
||||||
paseoWorktree: PaseoWorktreeForCwd;
|
paseoWorktree: PaseoWorktreeForCwd;
|
||||||
storedBaseRef: string | null;
|
storedBaseRef: string | null;
|
||||||
resolvedBaseRef: string | null;
|
resolvedBaseRef: string | null;
|
||||||
@@ -817,7 +819,13 @@ export async function getMainRepoRoot(cwd: string): Promise<string> {
|
|||||||
cwd,
|
cwd,
|
||||||
envOverlay: READ_ONLY_GIT_ENV,
|
envOverlay: READ_ONLY_GIT_ENV,
|
||||||
});
|
});
|
||||||
const commonDir = resolveGitRevParsePath(cwd, commonDirOut);
|
return getMainRepoRootFromCommonDir(cwd, resolveGitRevParsePath(cwd, commonDirOut));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMainRepoRootFromCommonDir(
|
||||||
|
cwd: string,
|
||||||
|
commonDir: string | null,
|
||||||
|
): Promise<string> {
|
||||||
if (!commonDir) {
|
if (!commonDir) {
|
||||||
throw new Error("Not in a git repository");
|
throw new Error("Not in a git repository");
|
||||||
}
|
}
|
||||||
@@ -1101,6 +1109,18 @@ export async function resolveAbsoluteGitDir(cwd: string): Promise<string | null>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resolveGitCommonDir(cwd: string): Promise<string | null> {
|
||||||
|
try {
|
||||||
|
const { stdout } = await runGitCommand(["rev-parse", "--git-common-dir"], {
|
||||||
|
cwd,
|
||||||
|
envOverlay: READ_ONLY_GIT_ENV,
|
||||||
|
});
|
||||||
|
return resolveGitRevParsePath(cwd, stdout);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function abortGitPullConflictState(cwd: string): Promise<void> {
|
async function abortGitPullConflictState(cwd: string): Promise<void> {
|
||||||
const gitDir = await resolveAbsoluteGitDir(cwd);
|
const gitDir = await resolveAbsoluteGitDir(cwd);
|
||||||
if (!gitDir) {
|
if (!gitDir) {
|
||||||
@@ -1389,6 +1409,8 @@ interface CheckoutInspectionContext {
|
|||||||
worktreeRoot: string;
|
worktreeRoot: string;
|
||||||
currentBranch: string | null;
|
currentBranch: string | null;
|
||||||
remoteUrl: string | null;
|
remoteUrl: string | null;
|
||||||
|
absoluteGitDir: string | null;
|
||||||
|
gitCommonDir: string | null;
|
||||||
paseoWorktree: PaseoWorktreeForCwd;
|
paseoWorktree: PaseoWorktreeForCwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1402,16 +1424,21 @@ async function inspectCheckoutContext(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [currentBranch, remoteUrl, paseoWorktree] = await Promise.all([
|
const [currentBranch, remoteUrl, absoluteGitDir, gitCommonDir, paseoWorktree] =
|
||||||
getCurrentBranch(cwd),
|
await Promise.all([
|
||||||
getOriginRemoteUrl(cwd),
|
getCurrentBranch(cwd),
|
||||||
getPaseoWorktreeForCwd(cwd, context, root),
|
getOriginRemoteUrl(cwd),
|
||||||
]);
|
resolveAbsoluteGitDir(cwd),
|
||||||
|
resolveGitCommonDir(cwd),
|
||||||
|
getPaseoWorktreeForCwd(cwd, context, root),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
worktreeRoot: root,
|
worktreeRoot: root,
|
||||||
currentBranch,
|
currentBranch,
|
||||||
remoteUrl,
|
remoteUrl,
|
||||||
|
absoluteGitDir,
|
||||||
|
gitCommonDir,
|
||||||
paseoWorktree,
|
paseoWorktree,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1464,7 +1491,9 @@ export async function getCheckoutSnapshotFacts(
|
|||||||
? readPaseoWorktreeBaseRef(inspected.paseoWorktree.worktreeRoot)
|
? readPaseoWorktreeBaseRef(inspected.paseoWorktree.worktreeRoot)
|
||||||
: null;
|
: null;
|
||||||
const resolvedBaseRef = storedBaseRef ?? (await resolveBaseRef(cwd));
|
const resolvedBaseRef = storedBaseRef ?? (await resolveBaseRef(cwd));
|
||||||
const mainRepoRoot = await getMainRepoRoot(cwd).catch(() => null);
|
const mainRepoRoot = await getMainRepoRootFromCommonDir(cwd, inspected.gitCommonDir).catch(
|
||||||
|
() => null,
|
||||||
|
);
|
||||||
let comparisonBaseRef: string | null = null;
|
let comparisonBaseRef: string | null = null;
|
||||||
if (
|
if (
|
||||||
resolvedBaseRef &&
|
resolvedBaseRef &&
|
||||||
@@ -1512,6 +1541,8 @@ export async function getCheckoutSnapshotFacts(
|
|||||||
worktreeRoot: inspected.worktreeRoot,
|
worktreeRoot: inspected.worktreeRoot,
|
||||||
currentBranch: inspected.currentBranch,
|
currentBranch: inspected.currentBranch,
|
||||||
remoteUrl: inspected.remoteUrl,
|
remoteUrl: inspected.remoteUrl,
|
||||||
|
absoluteGitDir: inspected.absoluteGitDir,
|
||||||
|
gitCommonDir: inspected.gitCommonDir,
|
||||||
paseoWorktree: inspected.paseoWorktree,
|
paseoWorktree: inspected.paseoWorktree,
|
||||||
storedBaseRef,
|
storedBaseRef,
|
||||||
resolvedBaseRef,
|
resolvedBaseRef,
|
||||||
|
|||||||
Reference in New Issue
Block a user