Skip to content

Commit 117396e

Browse files
committed
Fixes #3514 avoids trying to delete main worktree branch
Also avoids attempting to delete the main worktree
1 parent 06fe0a9 commit 117396e

File tree

9 files changed

+67
-33
lines changed

9 files changed

+67
-33
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- Fixes [#3514](https://github.com/gitkraken/vscode-gitlens/issues/3514) - Attempting to delete the main worktree's branch causes a invalid prompt to delete the main worktree
12+
913
## [15.4.0] - 2024-09-04
1014

1115
### Added

package.json

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13968,12 +13968,12 @@
1396813968
},
1396913969
{
1397013970
"command": "gitlens.views.switchToAnotherBranch",
13971-
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+current\\b)(?!.*?\\b\\+closed\\b)/",
13971+
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(current|main)\\b)(?!.*?\\b\\+closed\\b)/",
1397213972
"group": "inline@7"
1397313973
},
1397413974
{
1397513975
"command": "gitlens.views.switchToBranch",
13976-
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|closed|worktree)\\b)/",
13976+
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|closed|main|worktree)\\b)/",
1397713977
"group": "inline@7"
1397813978
},
1397913979
{
@@ -14064,17 +14064,17 @@
1406414064
},
1406514065
{
1406614066
"command": "gitlens.views.openInWorktree",
14067-
"when": "!listMultiSelection && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|closed|worktree)\\b)/",
14067+
"when": "!listMultiSelection && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|closed|main|worktree)\\b)/",
1406814068
"group": "1_gitlens_action@3"
1406914069
},
1407014070
{
1407114071
"command": "gitlens.views.switchToAnotherBranch",
14072-
"when": "!listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+current\\b)(?!.*?\\b\\+closed\\b)/",
14072+
"when": "!listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(current|main)\\b)(?!.*?\\b\\+closed\\b)/",
1407314073
"group": "1_gitlens_action@1"
1407414074
},
1407514075
{
1407614076
"command": "gitlens.views.switchToBranch",
14077-
"when": "!listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|closed|worktree)\\b)/",
14077+
"when": "!listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|closed|main|worktree)\\b)/",
1407814078
"group": "1_gitlens_action@1"
1407914079
},
1408014080
{
@@ -14119,12 +14119,12 @@
1411914119
},
1412014120
{
1412114121
"command": "gitlens.views.deleteBranch",
14122-
"when": "!listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)(?!.*?\\b\\+closed\\b)/",
14122+
"when": "!listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|main)\\b)(?!.*?\\b\\+closed\\b)/",
1412314123
"group": "1_gitlens_actions@7"
1412414124
},
1412514125
{
1412614126
"command": "gitlens.views.deleteBranch.multi",
14127-
"when": "listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)(?!.*?\\b\\+closed\\b)/",
14127+
"when": "listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|main)\\b)(?!.*?\\b\\+closed\\b)/",
1412814128
"group": "1_gitlens_actions@7"
1412914129
},
1413014130
{
@@ -15585,17 +15585,17 @@
1558515585
},
1558615586
{
1558715587
"command": "gitlens.graph.openInWorktree",
15588-
"when": "!gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|worktree)\\b)/",
15588+
"when": "!gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|main|worktree)\\b)/",
1558915589
"group": "1_gitlens_action@3"
1559015590
},
1559115591
{
1559215592
"command": "gitlens.graph.switchToAnotherBranch",
15593-
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+current\\b)/",
15593+
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(current|main)\\b)/",
1559415594
"group": "1_gitlens_action@1"
1559515595
},
1559615596
{
1559715597
"command": "gitlens.graph.switchToBranch",
15598-
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|worktree)\\b)/",
15598+
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|main|worktree)\\b)/",
1559915599
"group": "1_gitlens_action@1"
1560015600
},
1560115601
{
@@ -15640,7 +15640,7 @@
1564015640
},
1564115641
{
1564215642
"command": "gitlens.graph.deleteBranch",
15643-
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)/",
15643+
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+(current|main)\\b)/",
1564415644
"group": "1_gitlens_actions@7"
1564515645
},
1564615646
{

src/commands/git/branch.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import type { GitBranchReference, GitReference } from '../../git/models/referenc
44
import { getNameWithoutRemote, getReferenceLabel, isRevisionReference } from '../../git/models/reference';
55
import { Repository } from '../../git/models/repository';
66
import type { GitWorktree } from '../../git/models/worktree';
7+
import { getWorktreesByBranch } from '../../git/models/worktree';
78
import type { QuickPickItemOfT } from '../../quickpicks/items/common';
89
import { createQuickPickSeparator } from '../../quickpicks/items/common';
910
import type { FlagsQuickPickItem } from '../../quickpicks/items/flags';
1011
import { createFlagsQuickPickItem } from '../../quickpicks/items/flags';
12+
import { ensureArray } from '../../system/array';
1113
import { pluralize } from '../../system/string';
1214
import type { ViewsWithRepositoryFolders } from '../../views/viewBase';
1315
import { getSteps } from '../gitCommands.utils';
@@ -437,6 +439,8 @@ export class BranchGitCommand extends QuickCommand {
437439
state.references = [state.references];
438440
}
439441

442+
const worktreesByBranch = await getWorktreesByBranch(state.repo, { includeMainWorktree: true });
443+
440444
if (
441445
state.counter < 3 ||
442446
state.references == null ||
@@ -445,7 +449,9 @@ export class BranchGitCommand extends QuickCommand {
445449
context.title = getTitle('Branches', state.subcommand);
446450

447451
const result = yield* pickBranchesStep(state, context, {
448-
filter: prune ? b => !b.current && Boolean(b.upstream?.missing) : b => !b.current,
452+
filter: prune
453+
? b => !b.current && Boolean(b.upstream?.missing) && !worktreesByBranch.get(b.id)?.main
454+
: b => !b.current && !worktreesByBranch.get(b.id)?.main,
449455
picked: state.references?.map(r => r.ref),
450456
placeholder: prune
451457
? 'Choose branches with missing upstreams to delete'
@@ -468,7 +474,7 @@ export class BranchGitCommand extends QuickCommand {
468474

469475
assertStateStepDeleteBranches(state);
470476

471-
const worktrees = await this.getWorktreesOfSelectedBranches(state);
477+
const worktrees = this.getSelectedWorktrees(state, worktreesByBranch);
472478
if (worktrees.length) {
473479
const result = yield* getSteps(
474480
this.container,
@@ -503,18 +509,20 @@ export class BranchGitCommand extends QuickCommand {
503509
}
504510
}
505511

506-
private async getWorktreesOfSelectedBranches(state: DeleteStepState | PruneStepState): Promise<GitWorktree[]> {
507-
const worktrees = await state.repo.getWorktrees();
508-
509-
const refs = new Set<string>(
510-
Array.isArray(state.references)
511-
? state.references.map(r => r.name)
512-
: state.references != null
513-
? [state.references.name]
514-
: undefined,
515-
);
512+
private getSelectedWorktrees(
513+
state: DeleteStepState | PruneStepState,
514+
worktreesByBranch: Map<string, GitWorktree>,
515+
): GitWorktree[] {
516+
const worktrees: GitWorktree[] = [];
517+
518+
for (const ref of ensureArray(state.references)) {
519+
const worktree = worktreesByBranch.get(ref.id!);
520+
if (worktree != null && !worktree.main) {
521+
worktrees.push(worktree);
522+
}
523+
}
516524

517-
return worktrees.filter(wt => wt.branch && refs.has(wt.branch.name));
525+
return worktrees;
518526
}
519527

520528
private *deleteCommandConfirmStep(

src/commands/openOnRemote.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { RemoteResourceType } from '../git/models/remoteResource';
99
import type { RemoteProvider } from '../git/remotes/remoteProvider';
1010
import { showGenericErrorMessage } from '../messages';
1111
import { showRemoteProviderPicker } from '../quickpicks/remoteProviderPicker';
12-
import { ensure } from '../system/array';
12+
import { ensureArray } from '../system/array';
1313
import { command } from '../system/command';
1414
import { Logger } from '../system/logger';
1515
import { pad, splitSingle } from '../system/string';
@@ -88,7 +88,7 @@ export class OpenOnRemoteCommand extends Command {
8888
}
8989

9090
try {
91-
const resources = ensure(args.resource)!;
91+
const resources = ensureArray(args.resource);
9292
for (const resource of resources) {
9393
await processResource.call(this, resource);
9494
}

src/env/node/git/localGitProvider.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,7 +2326,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
23262326
this.getBranches(repoPath),
23272327
this.getRemotes(repoPath),
23282328
this.getCurrentUser(repoPath),
2329-
getWorktreesByBranch(this.container.git.getRepository(repoPath)),
2329+
getWorktreesByBranch(this.container.git.getRepository(repoPath), { includeMainWorktree: true }),
23302330
]);
23312331

23322332
const branches = getSettledValue(branchesResult)?.values;
@@ -2335,6 +2335,14 @@ export class LocalGitProvider implements GitProvider, Disposable {
23352335
const headRefUpstreamName = headBranch?.upstream?.name;
23362336
const worktreesByBranch = getSettledValue(worktreesByBranchResult);
23372337

2338+
let branchIdOfMainWorktree: string | undefined;
2339+
if (worktreesByBranch != null) {
2340+
branchIdOfMainWorktree = find(worktreesByBranch, ([, wt]) => wt.main)?.[0];
2341+
if (branchIdOfMainWorktree != null) {
2342+
worktreesByBranch.delete(branchIdOfMainWorktree);
2343+
}
2344+
}
2345+
23382346
const currentUser = getSettledValue(currentUserResult);
23392347

23402348
const remotes = getSettledValue(remotesResult);
@@ -2607,7 +2615,13 @@ export class LocalGitProvider implements GitProvider, Disposable {
26072615
context = {
26082616
webviewItem: `gitlens:branch${head ? '+current' : ''}${
26092617
branch?.upstream != null ? '+tracking' : ''
2610-
}${worktreesByBranch?.has(branchId) ? '+worktree' : ''}`,
2618+
}${
2619+
worktreesByBranch?.has(branchId)
2620+
? '+worktree'
2621+
: branchIdOfMainWorktree === branchId
2622+
? '+main'
2623+
: ''
2624+
}`,
26112625
webviewItemValue: {
26122626
type: 'branch',
26132627
ref: createReference(tip, repoPath, {

src/git/models/worktree.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,17 @@ export function sortWorktrees(worktrees: GitWorktree[] | WorktreeQuickPickItem[]
337337
}
338338
}
339339

340-
export async function getWorktreesByBranch(repos: Repository | Repository[] | undefined) {
340+
export async function getWorktreesByBranch(
341+
repos: Repository | Repository[] | undefined,
342+
options?: { includeMainWorktree?: boolean },
343+
) {
341344
const worktreesByBranch = new Map<string, GitWorktree>();
342345
if (repos == null) return worktreesByBranch;
343346

344347
async function addWorktrees(repo: Repository) {
345348
const worktrees = await repo.getWorktrees();
346349
for (const wt of worktrees) {
347-
if (wt.branch == null || wt.main) continue;
350+
if (wt.branch == null || (!options?.includeMainWorktree && wt.main)) continue;
348351

349352
worktreesByBranch.set(wt.branch.id, wt);
350353
}

src/system/array.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ export function countUniques<T>(source: T[], accessor: (item: T) => string): Rec
2828
return uniqueCounts;
2929
}
3030

31-
export function ensure<T>(source: T | T[] | undefined): T[] | undefined {
31+
export function ensureArray<T>(source: T | T[]): T[];
32+
export function ensureArray<T>(source: T | T[] | undefined): T[] | undefined;
33+
export function ensureArray<T>(source: T | T[] | undefined): T[] | undefined {
3234
return source == null ? undefined : Array.isArray(source) ? source : [source];
3335
}
3436

src/views/branchesView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export class BranchesViewNode extends RepositoriesSubscribeableNode<BranchesView
6868
this.view.message = undefined;
6969

7070
// Get all the worktree branches (and track if they are opened) to pass along downstream, e.g. in the BranchNode to display an indicator
71-
const worktreesByBranch = await getWorktreesByBranch(repositories);
71+
const worktreesByBranch = await getWorktreesByBranch(repositories, { includeMainWorktree: true });
7272
this.updateContext({
7373
worktreesByBranch: worktreesByBranch?.size ? worktreesByBranch : undefined,
7474
});

src/views/nodes/branchNode.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ export class BranchNode
136136
}
137137

138138
get worktree(): GitWorktree | undefined {
139-
return this.context.worktreesByBranch?.get(this.branch.id);
139+
const worktree = this.context.worktreesByBranch?.get(this.branch.id);
140+
return worktree?.main ? undefined : worktree;
140141
}
141142

142143
private _children: ViewNode[] | undefined;
@@ -449,6 +450,8 @@ export class BranchNode
449450
}
450451
if (worktree != null) {
451452
contextValue += '+worktree';
453+
} else if (this.context.worktreesByBranch?.get(this.branch.id)?.main) {
454+
contextValue += '+main';
452455
}
453456
// TODO@axosoft-ramint Temporary workaround, remove when our git commands work on closed repos.
454457
if (this.repo.closed) {

0 commit comments

Comments
 (0)