@@ -762,8 +762,6 @@ export class CommandCenter {
762762 private disposables : Disposable [ ] ;
763763 private commandErrors = new CommandErrorOutputTextDocumentContentProvider ( ) ;
764764
765- private static readonly WORKTREE_ROOT_KEY = 'worktreeRoot' ;
766-
767765 constructor (
768766 private git : Git ,
769767 private model : Model ,
@@ -3500,119 +3498,47 @@ export class CommandCenter {
35003498 } ) ;
35013499 }
35023500
3503- @command ( 'git.createWorktreeWithDefaults' , { repository : true , repositoryFilter : [ 'repository' ] } )
3504- async createWorktreeWithDefaults (
3505- repository : Repository ,
3506- commitish : string = 'HEAD'
3507- ) : Promise < string | undefined > {
3508- const config = workspace . getConfiguration ( 'git' ) ;
3509- const branchPrefix = config . get < string > ( 'branchPrefix' , '' ) ;
3510-
3511- // Generate branch name if not provided
3512- let branch = await this . generateRandomBranchName ( repository , '-' ) ;
3513- if ( ! branch ) {
3514- // Fallback to timestamp-based name if random generation fails
3515- const timestamp = new Date ( ) . toISOString ( ) . replace ( / [: .] / g, '-' ) . slice ( 0 , 19 ) ;
3516- branch = `${ branchPrefix } worktree-${ timestamp } ` ;
3517- }
3518-
3519- // Ensure branch name starts with prefix if configured
3520- if ( branchPrefix && ! branch . startsWith ( branchPrefix ) ) {
3521- branch = branchPrefix + branch ;
3522- }
3523-
3524- // Create worktree name from branch name
3525- const worktreeName = branch . startsWith ( branchPrefix )
3526- ? branch . substring ( branchPrefix . length ) . replace ( / \/ / g, '-' )
3527- : branch . replace ( / \/ / g, '-' ) ;
3528-
3529- // Determine default worktree path
3530- const defaultWorktreeRoot = this . globalState . get < string > ( `${ CommandCenter . WORKTREE_ROOT_KEY } :${ repository . root } ` ) ;
3531- const defaultWorktreePath = defaultWorktreeRoot
3532- ? path . join ( defaultWorktreeRoot , worktreeName )
3533- : path . join ( path . dirname ( repository . root ) , `${ path . basename ( repository . root ) } .worktrees` , worktreeName ) ;
3534-
3535- // Check if worktree already exists at this path
3536- const existingWorktree = repository . worktrees . find ( worktree =>
3537- pathEquals ( path . normalize ( worktree . path ) , path . normalize ( defaultWorktreePath ) )
3538- ) ;
3539-
3540- if ( existingWorktree ) {
3541- // Generate unique path by appending a number
3542- let counter = 1 ;
3543- let uniquePath = `${ defaultWorktreePath } -${ counter } ` ;
3544- while ( repository . worktrees . some ( wt => pathEquals ( path . normalize ( wt . path ) , path . normalize ( uniquePath ) ) ) ) {
3545- counter ++ ;
3546- uniquePath = `${ defaultWorktreePath } -${ counter } ` ;
3547- }
3548- const finalWorktreePath = uniquePath ;
3549-
3550- try {
3551- await repository . addWorktree ( { path : finalWorktreePath , branch, commitish } ) ;
3552-
3553- // Update worktree root in global state
3554- const worktreeRoot = path . dirname ( finalWorktreePath ) ;
3555- if ( worktreeRoot !== defaultWorktreeRoot ) {
3556- this . globalState . update ( `${ CommandCenter . WORKTREE_ROOT_KEY } :${ repository . root } ` , worktreeRoot ) ;
3557- }
3558-
3559- return finalWorktreePath ;
3560- } catch ( err ) {
3561- // Return undefined on failure
3562- return undefined ;
3563- }
3564- }
3565-
3566- try {
3567- await repository . addWorktree ( { path : defaultWorktreePath , branch, commitish } ) ;
3568-
3569- // Update worktree root in global state
3570- const worktreeRoot = path . dirname ( defaultWorktreePath ) ;
3571- if ( worktreeRoot !== defaultWorktreeRoot ) {
3572- this . globalState . update ( `${ CommandCenter . WORKTREE_ROOT_KEY } :${ repository . root } ` , worktreeRoot ) ;
3573- }
3574-
3575- return defaultWorktreePath ;
3576- } catch ( err ) {
3577- // Return undefined on failure
3578- return undefined ;
3579- }
3580- }
3581-
3582- @command ( 'git.createWorktree' , { repository : true } )
3501+ @command ( 'git.createWorktree' , { repository : true , repositoryFilter : [ 'repository' , 'submodule' ] } )
35833502 async createWorktree ( repository ?: Repository ) : Promise < void > {
35843503 if ( ! repository ) {
3585- // Single repository/submodule/worktree
3586- if ( this . model . repositories . length === 1 ) {
3587- repository = this . model . repositories [ 0 ] ;
3588- }
3504+ return ;
35893505 }
35903506
3591- if ( ! repository ) {
3592- // Single repository/submodule
3593- const repositories = this . model . repositories
3594- . filter ( r => r . kind === 'repository' || r . kind === 'submodule' ) ;
3507+ const config = workspace . getConfiguration ( 'git' ) ;
3508+ const branchPrefix = config . get < string > ( 'branchPrefix' ) ! ;
35953509
3596- if ( repositories . length === 1 ) {
3597- repository = repositories [ 0 ] ;
3598- }
3510+ // Get commitish and branch for the new worktree
3511+ const worktreeDetails = await this . getWorktreeCommitishAndBranch ( repository ) ;
3512+ if ( ! worktreeDetails ) {
3513+ return ;
35993514 }
36003515
3601- if ( ! repository ) {
3602- // Multiple repositories/submodules
3603- repository = await this . model . pickRepository ( [ 'repository' , 'submodule' ] ) ;
3604- }
3516+ const { commitish , branch } = worktreeDetails ;
3517+ const worktreeName = ( ( branch ?? commitish ) . startsWith ( branchPrefix )
3518+ ? ( branch ?? commitish ) . substring ( branchPrefix . length ) . replace ( / \/ / g , '-' )
3519+ : ( branch ?? commitish ) . replace ( / \/ / g , '-' ) ) ;
36053520
3606- if ( ! repository ) {
3521+ // Get path for the new worktree
3522+ const worktreePath = await this . getWorktreePath ( repository , worktreeName ) ;
3523+ if ( ! worktreePath ) {
36073524 return ;
36083525 }
36093526
3610- await this . _createWorktree ( repository ) ;
3527+ try {
3528+ await repository . createWorktree ( { path : worktreePath , branch, commitish : commitish } ) ;
3529+ } catch ( err ) {
3530+ if ( err instanceof GitError && err . gitErrorCode === GitErrorCodes . WorktreeAlreadyExists ) {
3531+ await this . handleWorktreeAlreadyExists ( err ) ;
3532+ } else if ( err instanceof GitError && err . gitErrorCode === GitErrorCodes . WorktreeBranchAlreadyUsed ) {
3533+ await this . handleWorktreeBranchAlreadyUsed ( err ) ;
3534+ } else {
3535+ throw err ;
3536+ }
3537+ }
36113538 }
36123539
3613- private async _createWorktree ( repository : Repository ) : Promise < void > {
3614- const config = workspace . getConfiguration ( 'git' ) ;
3615- const branchPrefix = config . get < string > ( 'branchPrefix' ) ! ;
3540+ private async getWorktreeCommitishAndBranch ( repository : Repository ) : Promise < { commitish : string ; branch : string | undefined } | undefined > {
3541+ const config = workspace . getConfiguration ( 'git' , Uri . file ( repository . root ) ) ;
36163542 const showRefDetails = config . get < boolean > ( 'showReferenceDetails' ) === true ;
36173543
36183544 const createBranch = new CreateBranchItem ( ) ;
@@ -3631,23 +3557,21 @@ export class CommandCenter {
36313557 const choice = await this . pickRef ( getBranchPicks ( ) , placeHolder ) ;
36323558
36333559 if ( ! choice ) {
3634- return ;
3560+ return undefined ;
36353561 }
36363562
3637- let branch : string | undefined = undefined ;
3638- let commitish : string ;
3639-
36403563 if ( choice === createBranch ) {
3641- branch = await this . promptForBranchName ( repository ) ;
3642-
3564+ // Create new branch
3565+ const branch = await this . promptForBranchName ( repository ) ;
36433566 if ( ! branch ) {
3644- return ;
3567+ return undefined ;
36453568 }
36463569
3647- commitish = 'HEAD' ;
3570+ return { commitish : 'HEAD' , branch } ;
36483571 } else {
3572+ // Existing reference
36493573 if ( ! ( choice instanceof RefItem ) || ! choice . refName ) {
3650- return ;
3574+ return undefined ;
36513575 }
36523576
36533577 if ( choice . refName === repository . HEAD ?. name ) {
@@ -3656,15 +3580,14 @@ export class CommandCenter {
36563580 const pick = await window . showWarningMessage ( message , { modal : true } , createBranch ) ;
36573581
36583582 if ( pick === createBranch ) {
3659- branch = await this . promptForBranchName ( repository ) ;
3660-
3583+ const branch = await this . promptForBranchName ( repository ) ;
36613584 if ( ! branch ) {
3662- return ;
3585+ return undefined ;
36633586 }
36643587
3665- commitish = 'HEAD' ;
3588+ return { commitish : 'HEAD' , branch } ;
36663589 } else {
3667- return ;
3590+ return undefined ;
36683591 }
36693592 } else {
36703593 // Check whether the selected branch is checked out in an existing worktree
@@ -3674,17 +3597,14 @@ export class CommandCenter {
36743597 await this . handleWorktreeConflict ( worktree . path , message ) ;
36753598 return ;
36763599 }
3677- commitish = choice . refName ;
3600+ return { commitish : choice . refName , branch : undefined } ;
36783601 }
36793602 }
3603+ }
36803604
3681- const worktreeName = ( ( branch ?? commitish ) . startsWith ( branchPrefix )
3682- ? ( branch ?? commitish ) . substring ( branchPrefix . length ) . replace ( / \/ / g, '-' )
3683- : ( branch ?? commitish ) . replace ( / \/ / g, '-' ) ) ;
3684-
3685- // If user selects folder button, they manually select the worktree path through folder picker
3605+ private async getWorktreePath ( repository : Repository , worktreeName : string ) : Promise < string | undefined > {
36863606 const getWorktreePath = async ( ) : Promise < string | undefined > => {
3687- const worktreeRoot = this . globalState . get < string > ( `${ CommandCenter . WORKTREE_ROOT_KEY } :${ repository . root } ` ) ;
3607+ const worktreeRoot = this . globalState . get < string > ( `${ Repository . WORKTREE_ROOT_STORAGE_KEY } :${ repository . root } ` ) ;
36883608 const defaultUri = worktreeRoot ? Uri . file ( worktreeRoot ) : Uri . file ( path . dirname ( repository . root ) ) ;
36893609
36903610 const uris = await window . showOpenDialog ( {
@@ -3720,7 +3640,7 @@ export class CommandCenter {
37203640 } ;
37213641
37223642 // Default worktree path is based on the last worktree location or a worktree folder for the repository
3723- const defaultWorktreeRoot = this . globalState . get < string > ( `${ CommandCenter . WORKTREE_ROOT_KEY } :${ repository . root } ` ) ;
3643+ const defaultWorktreeRoot = this . globalState . get < string > ( `${ Repository . WORKTREE_ROOT_STORAGE_KEY } :${ repository . root } ` ) ;
37243644 const defaultWorktreePath = defaultWorktreeRoot
37253645 ? path . join ( defaultWorktreeRoot , worktreeName )
37263646 : path . join ( path . dirname ( repository . root ) , `${ path . basename ( repository . root ) } .worktrees` , worktreeName ) ;
@@ -3759,29 +3679,7 @@ export class CommandCenter {
37593679
37603680 dispose ( disposables ) ;
37613681
3762- if ( ! worktreePath ) {
3763- return ;
3764- }
3765-
3766- try {
3767- await repository . addWorktree ( { path : worktreePath , branch, commitish : commitish } ) ;
3768-
3769- // Update worktree root in global state
3770- const worktreeRoot = path . dirname ( worktreePath ) ;
3771- if ( worktreeRoot !== defaultWorktreeRoot ) {
3772- this . globalState . update ( `${ CommandCenter . WORKTREE_ROOT_KEY } :${ repository . root } ` , worktreeRoot ) ;
3773- }
3774- } catch ( err ) {
3775- if ( err instanceof GitError && err . gitErrorCode === GitErrorCodes . WorktreeAlreadyExists ) {
3776- await this . handleWorktreeAlreadyExists ( err ) ;
3777- } else if ( err instanceof GitError && err . gitErrorCode === GitErrorCodes . WorktreeBranchAlreadyUsed ) {
3778- await this . handleWorktreeBranchAlreadyUsed ( err ) ;
3779- } else {
3780- throw err ;
3781- }
3782-
3783- return ;
3784- }
3682+ return worktreePath ;
37853683 }
37863684
37873685 private async handleWorktreeBranchAlreadyUsed ( err : GitError ) : Promise < void > {
0 commit comments