Skip to content

Commit 6187e6d

Browse files
Git: Delete Worktree... command for command palette only (microsoft#256827)
* Delete worktree picker command palette * clean up * Only allow delete worktree picker from main repository * Find main repository * resolve hygiene formatting issues
1 parent 88b415f commit 6187e6d

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

extensions/git/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,12 @@
551551
"category": "Git",
552552
"enablement": "!operationInProgress"
553553
},
554+
{
555+
"command": "git.deleteWorktreeFromPalette",
556+
"title": "%command.deleteWorktreeFromPalette%",
557+
"category": "Git",
558+
"enablement": "!operationInProgress"
559+
},
554560
{
555561
"command": "git.graph.deleteTag",
556562
"title": "%command.graphDeleteTag%",
@@ -1309,6 +1315,10 @@
13091315
"command": "git.deleteWorktree",
13101316
"when": "false"
13111317
},
1318+
{
1319+
"command": "git.deleteWorktreeFromPalette",
1320+
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount > 1"
1321+
},
13121322
{
13131323
"command": "git.deleteRemoteTag",
13141324
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"

extensions/git/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"command.deleteTag": "Delete Tag...",
7878
"command.createWorktree": "Create Worktree...",
7979
"command.deleteWorktree": "Delete Worktree",
80+
"command.deleteWorktreeFromPalette": "Delete Worktree...",
8081
"command.deleteRemoteTag": "Delete Remote Tag...",
8182
"command.fetch": "Fetch",
8283
"command.fetchPrune": "Fetch (Prune)",

extensions/git/src/commands.ts

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Command, commands, Disposable, MessageOptions, Position, ProgressLocati
99
import TelemetryReporter from '@vscode/extension-telemetry';
1010
import { uniqueNamesGenerator, adjectives, animals, colors, NumberDictionary } from '@joaomoreno/unique-names-generator';
1111
import { ForcePushMode, GitErrorCodes, RefType, Status, CommitOptions, RemoteSourcePublisher, Remote, Branch, Ref } from './api/git';
12-
import { Git, Stash } from './git';
12+
import { Git, Stash, Worktree } from './git';
1313
import { Model } from './model';
1414
import { GitResourceGroup, Repository, Resource, ResourceGroupType } from './repository';
1515
import { DiffEditorSelectionHunkToolbarContext, LineChange, applyLineChanges, getIndexDiffInformation, getModifiedRange, getWorkingTreeDiffInformation, intersectDiffWithRange, invertLineChange, toLineChanges, toLineRanges, compareLineChanges } from './staging';
@@ -57,6 +57,19 @@ class RefItemSeparator implements QuickPickItem {
5757
constructor(private readonly refType: RefType) { }
5858
}
5959

60+
class WorktreeItem implements QuickPickItem {
61+
62+
get label(): string {
63+
return `$(list-tree) ${this.worktree.name}`;
64+
}
65+
66+
get description(): string {
67+
return this.worktree.path;
68+
}
69+
70+
constructor(readonly worktree: Worktree) { }
71+
}
72+
6073
class RefItem implements QuickPickItem {
6174

6275
get label(): string {
@@ -215,6 +228,29 @@ class RemoteTagDeleteItem extends RefItem {
215228
}
216229
}
217230

231+
class WorktreeDeleteItem extends WorktreeItem {
232+
async run(mainRepository: Repository): Promise<void> {
233+
if (!this.worktree.path) {
234+
return;
235+
}
236+
237+
try {
238+
await mainRepository.deleteWorktree(this.worktree.path);
239+
} catch (err) {
240+
if (err.gitErrorCode === GitErrorCodes.WorktreeContainsChanges) {
241+
const forceDelete = l10n.t('Force Delete');
242+
const message = l10n.t('The worktree contains modified or untracked files. Do you want to force delete?');
243+
const choice = await window.showWarningMessage(message, { modal: true }, forceDelete);
244+
245+
if (choice === forceDelete) {
246+
await mainRepository.deleteWorktree(this.worktree.path, { force: true });
247+
}
248+
}
249+
}
250+
}
251+
}
252+
253+
218254
class MergeItem extends BranchItem {
219255

220256
async run(repository: Repository): Promise<void> {
@@ -3420,6 +3456,32 @@ export class CommandCenter {
34203456
}
34213457
}
34223458

3459+
@command('git.deleteWorktreeFromPalette')
3460+
async deleteWorktreeFromPalette(): Promise<void> {
3461+
const mainRepository = this.model.repositories.find(repo =>
3462+
!repo.dotGit.commonPath
3463+
);
3464+
3465+
if (!mainRepository) {
3466+
return;
3467+
}
3468+
3469+
const worktreePicks = async (): Promise<WorktreeDeleteItem[] | QuickPickItem[]> => {
3470+
const worktrees = await mainRepository.getWorktrees();
3471+
return worktrees.length === 0
3472+
? [{ label: l10n.t('$(info) This repository has no worktrees.') }]
3473+
: worktrees.map(worktree => new WorktreeDeleteItem(worktree));
3474+
};
3475+
3476+
const placeHolder = l10n.t('Select a worktree to delete');
3477+
const choice = await this.pickRef<WorktreeDeleteItem | QuickPickItem>(worktreePicks(), placeHolder);
3478+
3479+
if (choice instanceof WorktreeDeleteItem) {
3480+
await choice.run(mainRepository);
3481+
}
3482+
}
3483+
3484+
34233485
@command('git.graph.deleteTag', { repository: true })
34243486
async deleteTag2(repository: Repository, historyItem?: SourceControlHistoryItem, historyItemRefId?: string): Promise<void> {
34253487
const historyItemRef = historyItem?.references?.find(r => r.id === historyItemRefId);

0 commit comments

Comments
 (0)