Start new workspaces from pasted pull requests (#2290)

* fix(workspaces): start pasted pull requests from their branch

Recognized pull request links now select their branch directly instead of
waiting for a separate confirmation. Ensure single-branch clones also record
the fetched branch so the new worktree can track it.

* fix(workspaces): keep pasted PR checkout target-safe

* fix(workspaces): make pasted PR resolution deterministic

* fix(workspaces): preserve explicit checkout selection

A recognized pull request selects itself only when its attachment is added. Once the user chooses a branch, later composer edits must not derive checkout state from existing attachments.

* fix(composer): ignore stale pull request lookups

A lookup may finish after the workspace target changes. Only apply its attachment and selection event when the host, working directory, client, and remote still match the target that started it.

* fix(workspaces): make checkout choices authoritative

Arm automatic pull request selection only when a new PR link is detected. An explicit picker choice cancels that pending selection, existing draft attachments never infer checkout state, and target changes suppress carried-over lookups.

* fix(workspaces): stabilize pull request auto-selection

Keep the first PR selected when one edit contains several links, and accept a completed lookup when only the transport client changed for the same host and checkout.

* fix(composer): release removed pull request lookups

Release each auto-attach invocation when its composer state is abandoned, while continuing to discard any stale response.
This commit is contained in:
Mohamed Boudra
2026-07-21 15:20:05 +02:00
committed by GitHub
parent fd4e13735c
commit 2cb1b041dd
20 changed files with 768 additions and 313 deletions
+27 -1
View File
@@ -1511,7 +1511,33 @@ async function tryFetchWorktreeTrackingRemote(options: {
acceptExitCodes: [0, 1, 128],
},
);
return result.exitCode === 0 ? { name: options.remoteName, headRef: options.headRef } : undefined;
if (result.exitCode !== 0) {
return undefined;
}
await ensureRemoteFetchesBranch(options);
return { name: options.remoteName, headRef: options.headRef };
}
async function ensureRemoteFetchesBranch(options: {
cwd: string;
remoteName: string;
headRef: string;
}): Promise<void> {
const configKey = `remote.${options.remoteName}.fetch`;
const exactRefspec = `refs/heads/${options.headRef}:refs/remotes/${options.remoteName}/${options.headRef}`;
const wildcardRefspec = `refs/heads/*:refs/remotes/${options.remoteName}/*`;
const { stdout } = await runGitCommand(["config", "--get-all", configKey], {
cwd: options.cwd,
acceptExitCodes: [0, 1],
});
const alreadyTracked = stdout
.split("\n")
.map((refspec) => refspec.trim().replace(/^\+/, ""))
.some((refspec) => refspec === exactRefspec || refspec === wildcardRefspec);
if (alreadyTracked) {
return;
}
await runGitCommand(["config", "--add", configKey, `+${exactRefspec}`], { cwd: options.cwd });
}
async function getWorktreeRemotePushUrl(