Skip to content

Commit ccab2f2

Browse files
Refines 'Create Worktree' Flow (#3559)
* Updates 'create worktree' flows - Auto-chooses "for new branch" option or not based on whether the chosen branch is already in a worktree. - If "new branch" option is chosen, shows prompt for new branch name before reaching the confirm step. * Fixes remote branch default name case * Fixes default option flag and path
1 parent 107c129 commit ccab2f2

File tree

2 files changed

+62
-67
lines changed

2 files changed

+62
-67
lines changed

src/commands/git/worktree.ts

Lines changed: 61 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
} from '../../git/models/reference';
2727
import type { Repository } from '../../git/models/repository';
2828
import type { GitWorktree } from '../../git/models/worktree';
29+
import { getWorktreeForBranch } from '../../git/models/worktree';
2930
import { showGenericErrorMessage } from '../../messages';
3031
import type { QuickPickItemOfT } from '../../quickpicks/items/common';
3132
import { createQuickPickSeparator } from '../../quickpicks/items/common';
@@ -86,6 +87,7 @@ type CreateFlags = '--force' | '-b' | '--detach' | '--direct';
8687
interface CreateState {
8788
subcommand: 'create';
8889
repo: string | Repository;
90+
worktree?: GitWorktree;
8991
uri: Uri;
9092
reference?: GitReference;
9193
addRemote?: { name: string; url: string };
@@ -410,6 +412,58 @@ export class WorktreeGitCommand extends QuickCommand<State> {
410412
state.uri = context.defaultUri!;
411413
}
412414

415+
state.worktree =
416+
isBranchReference(state.reference) && !state.reference.remote
417+
? await getWorktreeForBranch(state.repo, state.reference.name, undefined, context.worktrees)
418+
: undefined;
419+
420+
const isRemoteBranch = isBranchReference(state.reference) && state.reference?.remote;
421+
if ((isRemoteBranch || state.worktree != null) && !state.flags.includes('-b')) {
422+
state.flags.push('-b');
423+
}
424+
425+
if (isRemoteBranch) {
426+
state.createBranch = getNameWithoutRemote(state.reference);
427+
const branch = await state.repo.getBranch(state.createBranch);
428+
if (branch != null && !branch.remote) {
429+
state.createBranch = branch.name;
430+
}
431+
}
432+
433+
if (state.flags.includes('-b')) {
434+
let createBranchOverride: string | undefined;
435+
if (state.createBranch != null) {
436+
let valid = await this.container.git.validateBranchOrTagName(state.repo.path, state.createBranch);
437+
if (valid) {
438+
const alreadyExists = await state.repo.getBranch(state.createBranch);
439+
valid = alreadyExists == null;
440+
}
441+
442+
if (!valid) {
443+
createBranchOverride = state.createBranch;
444+
state.createBranch = undefined;
445+
}
446+
}
447+
448+
if (state.createBranch == null) {
449+
const result = yield* inputBranchNameStep(state, context, {
450+
titleContext: ` and New Branch from ${getReferenceLabel(state.reference, {
451+
capitalize: true,
452+
icon: false,
453+
label: state.reference.refType !== 'branch',
454+
})}`,
455+
value: createBranchOverride ?? getNameWithoutRemote(state.reference),
456+
});
457+
if (result === StepResultBreak) {
458+
// Clear the flags, since we can backup after the confirm step below (which is non-standard)
459+
state.flags = [];
460+
continue;
461+
}
462+
463+
state.createBranch = result;
464+
}
465+
}
466+
413467
if (this.confirm(state.confirm)) {
414468
const result = yield* this.createCommandConfirmStep(state, context);
415469
if (result === StepResultBreak) continue;
@@ -456,51 +510,6 @@ export class WorktreeGitCommand extends QuickCommand<State> {
456510
state.confirm = true;
457511
this._canSkipConfirmOverride = undefined;
458512

459-
const isRemoteBranch = state.reference?.refType === 'branch' && state.reference?.remote;
460-
if (isRemoteBranch && !state.flags.includes('-b')) {
461-
state.flags.push('-b');
462-
463-
state.createBranch = getNameWithoutRemote(state.reference);
464-
const branch = await state.repo.getBranch(state.createBranch);
465-
if (branch != null) {
466-
state.createBranch = state.reference.name;
467-
}
468-
}
469-
470-
if (state.flags.includes('-b')) {
471-
let createBranchOverride: string | undefined;
472-
if (state.createBranch != null) {
473-
let valid = await this.container.git.validateBranchOrTagName(state.repo.path, state.createBranch);
474-
if (valid) {
475-
const alreadyExists = await state.repo.getBranch(state.createBranch);
476-
valid = alreadyExists == null;
477-
}
478-
479-
if (!valid) {
480-
createBranchOverride = state.createBranch;
481-
state.createBranch = undefined;
482-
}
483-
}
484-
485-
if (state.createBranch == null) {
486-
const result = yield* inputBranchNameStep(state, context, {
487-
titleContext: ` and New Branch from ${getReferenceLabel(state.reference, {
488-
capitalize: true,
489-
icon: false,
490-
label: state.reference.refType !== 'branch',
491-
})}`,
492-
value: createBranchOverride ?? state.createBranch ?? getNameWithoutRemote(state.reference),
493-
});
494-
if (result === StepResultBreak) {
495-
// Clear the flags, since we can backup after the confirm step below (which is non-standard)
496-
state.flags = [];
497-
continue;
498-
}
499-
500-
state.createBranch = result;
501-
}
502-
}
503-
504513
const uri = state.flags.includes('--direct')
505514
? state.uri
506515
: Uri.joinPath(
@@ -708,42 +717,28 @@ export class WorktreeGitCommand extends QuickCommand<State> {
708717
type StepType = FlagsQuickPickItem<CreateFlags, CreateConfirmationChoice>;
709718
const defaultOption = createFlagsQuickPickItem<CreateFlags, Uri>(
710719
state.flags,
711-
[],
720+
state.createBranch ? ['-b'] : [],
712721
{
713722
label: isRemoteBranch
714723
? 'Create Worktree for New Local Branch'
715724
: isBranch
716725
? 'Create Worktree for Branch'
717726
: context.title,
718727
description: '',
719-
detail: `Will create worktree in $(folder) ${recommendedFriendlyPath}`,
728+
detail: `Will create worktree in $(folder) ${
729+
state.createBranch ? recommendedNewBranchFriendlyPath : recommendedFriendlyPath
730+
}`,
720731
},
721732
recommendedRootUri,
722733
);
723734

724735
const confirmations: StepType[] = [];
725736
if (!createDirectlyInFolder) {
726-
if (!state.createBranch) {
727-
if (state.skipWorktreeConfirmations) {
728-
return [defaultOption.context, defaultOption.item];
729-
}
730-
confirmations.push(defaultOption);
737+
if (!state.createBranch && state.skipWorktreeConfirmations) {
738+
return [defaultOption.context, defaultOption.item];
731739
}
732740

733-
confirmations.push(
734-
createFlagsQuickPickItem<CreateFlags, Uri>(
735-
state.flags,
736-
['-b'],
737-
{
738-
label: isRemoteBranch
739-
? 'Create Worktree for New Local Branch Named...'
740-
: 'Create Worktree for New Branch Named...',
741-
description: '',
742-
detail: `Will create worktree in $(folder) ${recommendedNewBranchFriendlyPath}`,
743-
},
744-
recommendedRootUri,
745-
),
746-
);
741+
confirmations.push(defaultOption);
747742
} else {
748743
if (!state.createBranch) {
749744
confirmations.push(

src/git/models/worktree.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ export function createWorktreeQuickPickItem(
219219
export async function getWorktreeForBranch(
220220
repo: Repository,
221221
branchName: string,
222-
upstreamNames: string | string[],
222+
upstreamNames?: string | string[],
223223
worktrees?: GitWorktree[],
224224
branches?: PageableResult<GitBranch> | Map<unknown, GitBranch>,
225225
): Promise<GitWorktree | undefined> {

0 commit comments

Comments
 (0)