@@ -46,13 +46,15 @@ import {
4646 CHAT_SETTINGS_NAMESPACE ,
4747 CHECKOUT_DEFAULT_BRANCH ,
4848 CHECKOUT_PULL_REQUEST_BASE_BRANCH ,
49+ DEFAULT_DELETION_METHOD ,
4950 DISABLE_AI_FEATURES ,
5051 GIT ,
5152 POST_DONE ,
5253 PR_SETTINGS_NAMESPACE ,
5354 PULL_BEFORE_CHECKOUT ,
5455 PULL_BRANCH ,
5556 REMOTES ,
57+ SELECT_WORKTREE ,
5658 UPSTREAM_REMOTE ,
5759} from '../common/settingKeys' ;
5860import { ITelemetry } from '../common/telemetry' ;
@@ -2148,35 +2150,89 @@ export class FolderRepositoryManager extends Disposable {
21482150 quickPick . items = [ { label : vscode . l10n . t ( 'No local branches to delete' ) , picked : false } ] ;
21492151 }
21502152
2151- let firstStep = true ;
2153+ let step : 'branches' | 'worktrees' | 'remotes' = 'branches' ;
2154+ let nonExistantBranches = new Set < string > ( ) ;
2155+ let branchPicks : readonly vscode . QuickPickItem [ ] = [ ] ;
2156+
2157+ const showWorktreeStep = ( worktreeItems : ( vscode . QuickPickItem & { worktreePath : string } ) [ ] ) => {
2158+ quickPick . canSelectMany = true ;
2159+ quickPick . value = '' ;
2160+ quickPick . placeholder = vscode . l10n . t ( 'Do you want to delete the associated worktrees?' ) ;
2161+ quickPick . items = worktreeItems ;
2162+ quickPick . selectedItems = worktreeItems . filter ( item => item . picked ) ;
2163+ step = 'worktrees' ;
2164+ } ;
2165+
2166+ const deleteBranchesAndShowRemoteStep = async ( ) => {
2167+ if ( branchPicks . length ) {
2168+ await vscode . window . withProgress ( { location : vscode . ProgressLocation . Notification , title : vscode . l10n . t ( 'Cleaning up' ) } , async ( progress ) => {
2169+ try {
2170+ await this . deleteBranches ( branchPicks , nonExistantBranches , progress , branchPicks . length , 0 , [ ] ) ;
2171+ } catch ( e ) {
2172+ quickPick . hide ( ) ;
2173+ vscode . window . showErrorMessage ( vscode . l10n . t ( 'Deleting branches failed: {0} {1}' , e . message , e . stderr ) ) ;
2174+ }
2175+ } ) ;
2176+ }
2177+
2178+ const remoteItems = await this . getRemoteDeletionItems ( nonExistantBranches ) ;
2179+ if ( remoteItems && remoteItems . length ) {
2180+ quickPick . canSelectMany = true ;
2181+ quickPick . placeholder = vscode . l10n . t ( 'Choose remotes you want to delete permanently' ) ;
2182+ quickPick . items = remoteItems ;
2183+ quickPick . selectedItems = remoteItems . filter ( item => item . picked ) ;
2184+ step = 'remotes' ;
2185+ } else {
2186+ quickPick . hide ( ) ;
2187+ }
2188+ } ;
2189+
21522190 quickPick . onDidAccept ( async ( ) => {
21532191 quickPick . busy = true ;
21542192
2155- if ( firstStep ) {
2156- const picks = quickPick . selectedItems ;
2157- const nonExistantBranches = new Set < string > ( ) ;
2158- if ( picks . length ) {
2159- await vscode . window . withProgress ( { location : vscode . ProgressLocation . Notification , title : vscode . l10n . t ( 'Cleaning up' ) } , async ( progress ) => {
2160- try {
2161- await this . deleteBranches ( picks , nonExistantBranches , progress , picks . length , 0 , [ ] ) ;
2162- } catch ( e ) {
2163- quickPick . hide ( ) ;
2164- vscode . window . showErrorMessage ( vscode . l10n . t ( 'Deleting branches failed: {0} {1}' , e . message , e . stderr ) ) ;
2165- }
2166- } ) ;
2193+ if ( step === 'branches' ) {
2194+ branchPicks = quickPick . selectedItems ;
2195+ nonExistantBranches = new Set < string > ( ) ;
2196+
2197+ // Find which selected branches have worktrees (must be deleted before the branch)
2198+ const preferredWorktreeDeletion = ! ! vscode . workspace
2199+ . getConfiguration ( PR_SETTINGS_NAMESPACE )
2200+ . get < boolean > ( `${ DEFAULT_DELETION_METHOD } .${ SELECT_WORKTREE } ` ) ;
2201+ const worktreeItems : ( vscode . QuickPickItem & { worktreePath : string } ) [ ] = [ ] ;
2202+ for ( const pick of branchPicks ) {
2203+ const worktreeUri = this . getWorktreeForBranch ( pick . label ) ;
2204+ if ( worktreeUri && ! vscode . workspace . workspaceFolders ?. some ( folder =>
2205+ folder . uri . fsPath === worktreeUri . fsPath ||
2206+ ( process . platform === 'win32' && folder . uri . fsPath . toLowerCase ( ) === worktreeUri . fsPath . toLowerCase ( ) )
2207+ ) ) {
2208+ worktreeItems . push ( {
2209+ label : pick . label ,
2210+ description : worktreeUri . fsPath ,
2211+ picked : preferredWorktreeDeletion ,
2212+ worktreePath : worktreeUri . fsPath ,
2213+ } ) ;
2214+ }
21672215 }
21682216
2169- firstStep = false ;
2170- const remoteItems = await this . getRemoteDeletionItems ( nonExistantBranches ) ;
2171-
2172- if ( remoteItems && remoteItems . length ) {
2173- quickPick . canSelectMany = true ;
2174- quickPick . placeholder = vscode . l10n . t ( 'Choose remotes you want to delete permanently' ) ;
2175- quickPick . items = remoteItems ;
2176- quickPick . selectedItems = remoteItems . filter ( item => item . picked ) ;
2217+ if ( worktreeItems . length && this . repository . deleteWorktree ) {
2218+ showWorktreeStep ( worktreeItems ) ;
21772219 } else {
2178- quickPick . hide ( ) ;
2220+ await deleteBranchesAndShowRemoteStep ( ) ;
2221+ }
2222+ } else if ( step === 'worktrees' ) {
2223+ const picks = quickPick . selectedItems as readonly ( vscode . QuickPickItem & { worktreePath : string } ) [ ] ;
2224+ if ( picks . length ) {
2225+ await vscode . window . withProgress ( { location : vscode . ProgressLocation . Notification , title : vscode . l10n . t ( 'Deleting {0} worktrees...' , picks . length ) } , async ( ) => {
2226+ for ( const pick of picks ) {
2227+ try {
2228+ await this . removeWorktree ( pick . worktreePath ) ;
2229+ } catch ( e ) {
2230+ Logger . error ( `Failed to delete worktree ${ pick . worktreePath } : ${ e } ` , this . id ) ;
2231+ }
2232+ }
2233+ } ) ;
21792234 }
2235+ await deleteBranchesAndShowRemoteStep ( ) ;
21802236 } else {
21812237 // batch deleting the remotes to avoid consuming all available resources
21822238 const picks = quickPick . selectedItems ;
0 commit comments