diff --git a/extensions/git/package.json b/extensions/git/package.json index 56055194944..cddee92cf55 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1662,10 +1662,27 @@ "scope": "resource" }, "git.checkoutType": { - "type": "string", - + "type": "array", + "items": { + "type": "string", + "enum": [ + "local", + "tags", + "remote" + ], + "enumDescriptions": [ + "%config.checkoutType.local%", + "%config.checkoutType.tags%", + "%config.checkoutType.remote%" + ] + }, + "uniqueItems": true, "markdownDescription": "%config.checkoutType%", - "default": "local,remote,tags" + "default": [ + "local", + "remote", + "tags" + ] }, "git.ignoreLegacyWarning": { "type": "boolean", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index bc09de34c05..1f37952eeaa 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -101,7 +101,10 @@ "config.countBadge.all": "Count all changes.", "config.countBadge.tracked": "Count only tracked changes.", "config.countBadge.off": "Turn off counter.", - "config.checkoutType": "Controls what type of branches (local, remote or tags, split with ',') are listed when running `Checkout to...`.", + "config.checkoutType": "Controls what type of git refs are listed when running `Checkout to...`.", + "config.checkoutType.local": "Local branches", + "config.checkoutType.tags": "Tags", + "config.checkoutType.remote": "Remote branches", "config.branchValidationRegex": "A regular expression to validate new branch names.", "config.branchWhitespaceChar": "The character to replace whitespace in new branch names.", "config.ignoreLegacyWarning": "Ignores the legacy Git warning.", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 1be44336f2d..90d5d6401c0 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -70,11 +70,6 @@ class CheckoutRemoteHeadItem extends CheckoutItem { } } -interface RefTypeAndCheckoutItem { - refType: RefType; - checkoutItemCtor: { new(ref: Ref): CheckoutItem; }; -} - class BranchDeleteItem implements QuickPickItem { private get shortCommit(): string { return (this.ref.commit || '').substr(0, 8); } @@ -212,37 +207,53 @@ async function categorizeResourceByResolution(resources: Resource[]): Promise<{ function createCheckoutItems(repository: Repository): CheckoutItem[] { const config = workspace.getConfiguration('git'); - const checkoutTypeString = config.get('checkoutType'); + const checkoutTypeConfig = config.get('checkoutType'); + let checkoutTypes: string[]; - const checkoutTypeOptions = ['local', 'remote', 'tags']; - const checkoutTypes = checkoutTypeString?.trim().split(',').map(type => type.trim()).filter(type => checkoutTypeOptions.includes(type)); + if (checkoutTypeConfig === 'all' || !checkoutTypeConfig || checkoutTypeConfig.length === 0) { + checkoutTypes = ['local', 'remote', 'tags']; + } else if (typeof checkoutTypeConfig === 'string') { + checkoutTypes = [checkoutTypeConfig]; + } else { + checkoutTypes = checkoutTypeConfig; + } - const results: CheckoutItem[] = []; - const seens = new Set(); - (checkoutTypes && checkoutTypes.length ? checkoutTypes : checkoutTypeOptions).forEach(type => { - if (seens.has(type)) { - return; + const processors = checkoutTypes.map(getCheckoutProcessor) + .filter(p => !!p) as CheckoutProcessor[]; + + for (const ref of repository.refs) { + for (const processor of processors) { + processor.onRef(ref); } - seens.add(type); + } - const { refType, checkoutItemCtor } = getRefTypeAndCheckoutItem(type); - results.push(...repository.refs.filter(ref => ref.type === refType).map(ref => new checkoutItemCtor(ref))); - }); - - return results; + return processors.reduce((r, p) => r.concat(...p.items), []); } -function getRefTypeAndCheckoutItem(type: string): RefTypeAndCheckoutItem { +class CheckoutProcessor { + + private refs: Ref[] = []; + get items(): CheckoutItem[] { return this.refs.map(r => new this.ctor(r)); } + constructor(private type: RefType, private ctor: { new(ref: Ref): CheckoutItem }) { } + + onRef(ref: Ref): void { + if (ref.type === this.type) { + this.refs.push(ref); + } + } +} + +function getCheckoutProcessor(type: string): CheckoutProcessor | undefined { switch (type) { case 'local': - return { refType: RefType.Head, checkoutItemCtor: CheckoutItem }; + return new CheckoutProcessor(RefType.Head, CheckoutItem); case 'remote': - return { refType: RefType.RemoteHead, checkoutItemCtor: CheckoutRemoteHeadItem }; + return new CheckoutProcessor(RefType.RemoteHead, CheckoutRemoteHeadItem); case 'tags': - return { refType: RefType.Tag, checkoutItemCtor: CheckoutTagItem }; - default: - throw new Error(`Unexpected type: ${type}`); + return new CheckoutProcessor(RefType.Tag, CheckoutTagItem); } + + return undefined; } function sanitizeRemoteName(name: string) {