@@ -825,6 +825,119 @@ export function registerCommands(
825825 ) ,
826826 ) ;
827827
828+ context . subscriptions . push (
829+ vscode . commands . registerCommand ( 'pr.pickInWorktree' , async ( pr : PRNode | RepositoryChangesNode | PullRequestModel ) => {
830+ if ( pr === undefined ) {
831+ Logger . error ( 'Unexpectedly received undefined when picking a PR for worktree checkout.' , logId ) ;
832+ return vscode . window . showErrorMessage ( vscode . l10n . t ( 'No pull request was selected to checkout, please try again.' ) ) ;
833+ }
834+
835+ let pullRequestModel : PullRequestModel ;
836+ let repository : Repository | undefined ;
837+
838+ if ( pr instanceof PRNode || pr instanceof RepositoryChangesNode ) {
839+ pullRequestModel = pr . pullRequestModel ;
840+ repository = pr . repository ;
841+ } else {
842+ pullRequestModel = pr ;
843+ }
844+
845+ // Validate that the PR has a valid head branch
846+ if ( ! pullRequestModel . head ) {
847+ return vscode . window . showErrorMessage ( vscode . l10n . t ( 'Unable to checkout pull request: missing head branch information.' ) ) ;
848+ }
849+
850+ // Get the folder manager to access the repository
851+ const folderManager = reposManager . getManagerForIssueModel ( pullRequestModel ) ;
852+ if ( ! folderManager ) {
853+ return vscode . window . showErrorMessage ( vscode . l10n . t ( 'Unable to find repository for this pull request.' ) ) ;
854+ }
855+
856+ const repositoryToUse = repository || folderManager . repository ;
857+
858+ /* __GDPR__
859+ "pr.checkoutInWorktree" : {}
860+ */
861+ telemetry . sendTelemetryEvent ( 'pr.checkoutInWorktree' ) ;
862+
863+ return vscode . window . withProgress (
864+ {
865+ location : vscode . ProgressLocation . Notification ,
866+ title : vscode . l10n . t ( 'Checking out Pull Request #{0} in worktree' , pullRequestModel . number ) ,
867+ } ,
868+ async ( progress ) => {
869+ // Generate a branch name for the worktree
870+ const branchName = pullRequestModel . head ! . ref ;
871+ const remoteName = pullRequestModel . remote . remoteName ;
872+
873+ // Fetch the PR branch first
874+ progress . report ( { message : vscode . l10n . t ( 'Fetching branch {0}...' , branchName ) } ) ;
875+ try {
876+ await repositoryToUse . fetch ( { remote : remoteName , ref : branchName } ) ;
877+ } catch ( e ) {
878+ Logger . appendLine ( `Failed to fetch branch ${ branchName } : ${ e } ` , logId ) ;
879+ // Continue even if fetch fails - the branch might already be available locally
880+ }
881+
882+ // Ask user for worktree location
883+ const repoRootPath = repositoryToUse . rootUri . fsPath ;
884+ const parentDir = pathLib . dirname ( repoRootPath ) ;
885+ const defaultWorktreePath = pathLib . join ( parentDir , `pr-${ pullRequestModel . number } ` ) ;
886+
887+ const worktreeUri = await vscode . window . showSaveDialog ( {
888+ defaultUri : vscode . Uri . file ( defaultWorktreePath ) ,
889+ title : vscode . l10n . t ( 'Select Worktree Location' ) ,
890+ saveLabel : vscode . l10n . t ( 'Create Worktree' ) ,
891+ } ) ;
892+
893+ if ( ! worktreeUri ) {
894+ return ; // User cancelled
895+ }
896+
897+ const worktreePath = worktreeUri . fsPath ;
898+
899+ // Create the worktree using git command
900+ progress . report ( { message : vscode . l10n . t ( 'Creating worktree at {0}...' , worktreePath ) } ) ;
901+
902+ const trackedBranchName = `${ remoteName } /${ branchName } ` ;
903+ const localBranchName = `pr-${ pullRequestModel . number } /${ branchName } ` ;
904+
905+ try {
906+ // Execute git worktree add command
907+ const terminal = vscode . window . createTerminal ( {
908+ name : vscode . l10n . t ( 'Git Worktree' ) ,
909+ cwd : repoRootPath ,
910+ hideFromUser : true ,
911+ } ) ;
912+
913+ // Create worktree with a new local branch tracking the remote
914+ terminal . sendText ( `git worktree add -b "${ localBranchName } " "${ worktreePath } " "${ trackedBranchName } " && exit` ) ;
915+
916+ // Wait a bit for the command to complete
917+ await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ;
918+
919+ terminal . dispose ( ) ;
920+
921+ // Ask user if they want to open the worktree
922+ const openAction = vscode . l10n . t ( 'Open in New Window' ) ;
923+ const result = await vscode . window . showInformationMessage (
924+ vscode . l10n . t ( 'Worktree created for Pull Request #{0}' , pullRequestModel . number ) ,
925+ openAction
926+ ) ;
927+
928+ if ( result === openAction ) {
929+ await commands . openFolder ( worktreeUri , { forceNewWindow : true } ) ;
930+ }
931+ } catch ( e ) {
932+ const errorMessage = e instanceof Error ? e . message : String ( e ) ;
933+ Logger . error ( `Failed to create worktree: ${ errorMessage } ` , logId ) ;
934+ return vscode . window . showErrorMessage ( vscode . l10n . t ( 'Failed to create worktree: {0}' , errorMessage ) ) ;
935+ }
936+ }
937+ ) ;
938+ } ) ,
939+ ) ;
940+
828941 context . subscriptions . push ( vscode . commands . registerCommand ( 'pr.checkoutOnVscodeDevFromDescription' , async ( context : BaseContext | undefined ) => {
829942 if ( ! context ) {
830943 return vscode . window . showErrorMessage ( vscode . l10n . t ( 'No pull request context provided for checkout.' ) ) ;
0 commit comments