Skip to content

Commit

Permalink
Changes tag parsing - hopefully fixes #855
Browse files Browse the repository at this point in the history
Unifies tag parsing to include msg, ref, & dates
Bumps required Git to 2.7.2
Adds more tag sorting options similar to branches
  • Loading branch information
eamodio committed Oct 9, 2019
1 parent bd92919 commit 358fa90
Show file tree
Hide file tree
Showing 17 changed files with 181 additions and 115 deletions.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1308,11 +1308,15 @@
"default": "name:desc",
"enum": [
"name:desc",
"name:asc"
"name:asc",
"date:desc",
"date:asc"
],
"enumDescriptions": [
"Sorts tags by name in descending order",
"Sorts tags by name in ascending order"
"Sorts tags by name in ascending order",
"Sorts tags by date in descending order",
"Sorts tags by date in ascending order"
],
"markdownDescription": "Specifies how tags are sorted in quick pick menus and views",
"scope": "window"
Expand Down
2 changes: 1 addition & 1 deletion src/commands/git/cherry-pick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class CherryPickGitCommand extends QuickCommandBase<State> {
)}(select or enter a reference)`,
matchOnDescription: true,
matchOnDetail: true,
items: await getBranchesAndOrTags(state.repo, true, {
items: await getBranchesAndOrTags(state.repo, ['branches', 'tags'], {
filterBranches: b => b.id !== destId
}),
onValidateValue: getValidateGitReferenceFn(state.repo)
Expand Down
2 changes: 1 addition & 1 deletion src/commands/git/merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export class MergeGitCommand extends QuickCommandBase<State> {
)}(select or enter a reference)`,
matchOnDescription: true,
matchOnDetail: true,
items: await getBranchesAndOrTags(state.repo, true, {
items: await getBranchesAndOrTags(state.repo, ['branches', 'tags'], {
filterBranches: b => b.id !== destId,
picked: state.reference && state.reference.ref
}),
Expand Down
2 changes: 1 addition & 1 deletion src/commands/git/rebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export class RebaseGitCommand extends QuickCommandBase<State> {
} onto${GlyphChars.Space.repeat(3)}(select or enter a reference)`,
matchOnDescription: true,
matchOnDetail: true,
items: await getBranchesAndOrTags(state.repo, true, {
items: await getBranchesAndOrTags(state.repo, ['branches', 'tags'], {
picked: state.reference && state.reference.ref
}),
additionalButtons: [pickBranchOrCommitButton],
Expand Down
4 changes: 2 additions & 2 deletions src/commands/git/switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export class SwitchGitCommand extends QuickCommandBase<State> {

const items = await getBranchesAndOrTags(
state.repos,
showTags,
showTags ? ['branches', 'tags'] : ['branches'],
state.repos.length === 1 ? undefined : { filterBranches: b => !b.remote }
);

Expand Down Expand Up @@ -171,7 +171,7 @@ export class SwitchGitCommand extends QuickCommandBase<State> {

quickpick.items = await getBranchesAndOrTags(
state.repos!,
showTags,
showTags ? ['branches', 'tags'] : ['branches'],
state.repos!.length === 1 ? undefined : { filterBranches: b => !b.remote }
);

Expand Down
60 changes: 39 additions & 21 deletions src/commands/quickCommand.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,19 @@ export async function getBranches(
repos: Repository | Repository[],
options: { filterBranches?: (b: GitBranch) => boolean; picked?: string | string[] } = {}
): Promise<BranchQuickPickItem[]> {
return getBranchesAndOrTags(repos, false, options) as Promise<BranchQuickPickItem[]>;
return getBranchesAndOrTags(repos, ['branches'], options) as Promise<BranchQuickPickItem[]>;
}

export async function getTags(
repos: Repository | Repository[],
options: { filterTags?: (t: GitTag) => boolean; picked?: string | string[] } = {}
): Promise<TagQuickPickItem[]> {
return getBranchesAndOrTags(repos, true, { ...options, filterBranches: () => false }) as Promise<
TagQuickPickItem[]
>;
return getBranchesAndOrTags(repos, ['tags'], options) as Promise<TagQuickPickItem[]>;
}

export async function getBranchesAndOrTags(
repos: Repository | Repository[],
includeTags: boolean,
include: ('tags' | 'branches')[],
{
filterBranches,
filterTags,
Expand All @@ -34,40 +32,44 @@ export async function getBranchesAndOrTags(
picked?: string | string[];
} = {}
): Promise<(BranchQuickPickItem | TagQuickPickItem)[]> {
let branches: GitBranch[];
let branches: GitBranch[] | undefined;
let tags: GitTag[] | undefined;

let singleRepo = false;
if (repos instanceof Repository || repos.length === 1) {
singleRepo = true;
const repo = repos instanceof Repository ? repos : repos[0];

[branches, tags] = await Promise.all<GitBranch[], GitTag[] | undefined>([
repo.getBranches({ filter: filterBranches, sort: true }),
includeTags ? repo.getTags({ filter: filterTags, includeRefs: true, sort: true }) : undefined
[branches, tags] = await Promise.all<GitBranch[] | undefined, GitTag[] | undefined>([
include.includes('branches') ? repo.getBranches({ filter: filterBranches, sort: true }) : undefined,
include.includes('tags') ? repo.getTags({ filter: filterTags, sort: true }) : undefined
]);
} else {
const [branchesByRepo, tagsByRepo] = await Promise.all<GitBranch[][], GitTag[][] | undefined>([
Promise.all(repos.map(r => r.getBranches({ filter: filterBranches, sort: true }))),
includeTags
? Promise.all(repos.map(r => r.getTags({ filter: filterTags, includeRefs: true, sort: true })))
const [branchesByRepo, tagsByRepo] = await Promise.all<GitBranch[][] | undefined, GitTag[][] | undefined>([
include.includes('branches')
? Promise.all(repos.map(r => r.getBranches({ filter: filterBranches, sort: true })))
: undefined,
include.includes('tags')
? Promise.all(repos.map(r => r.getTags({ filter: filterTags, sort: true })))
: undefined
]);

branches = GitBranch.sort(
Arrays.intersection(...branchesByRepo, ((b1: GitBranch, b2: GitBranch) => b1.name === b2.name) as any)
);
if (include.includes('branches')) {
branches = GitBranch.sort(
Arrays.intersection(...branchesByRepo!, ((b1: GitBranch, b2: GitBranch) => b1.name === b2.name) as any)
);
}

if (includeTags) {
if (include.includes('tags')) {
tags = GitTag.sort(
Arrays.intersection(...tagsByRepo!, ((t1: GitTag, t2: GitTag) => t1.name === t2.name) as any)
);
}
}

if (!includeTags) {
if (include.includes('branches') && !include.includes('tags')) {
return Promise.all(
branches.map(b =>
branches!.map(b =>
BranchQuickPickItem.create(
b,
picked != null && (typeof picked === 'string' ? b.ref === picked : picked.includes(b.ref)),
Expand All @@ -82,8 +84,23 @@ export async function getBranchesAndOrTags(
);
}

if (include.includes('tags') && !include.includes('branches')) {
return Promise.all(
tags!.map(t =>
TagQuickPickItem.create(
t,
picked != null && (typeof picked === 'string' ? t.ref === picked : picked.includes(t.ref)),
{
message: singleRepo,
ref: singleRepo
}
)
)
);
}

return Promise.all<BranchQuickPickItem | TagQuickPickItem>([
...branches
...branches!
.filter(b => !b.remote)
.map(b =>
BranchQuickPickItem.create(
Expand All @@ -101,12 +118,13 @@ export async function getBranchesAndOrTags(
t,
picked != null && (typeof picked === 'string' ? t.ref === picked : picked.includes(t.ref)),
{
message: singleRepo,
ref: singleRepo,
type: true
}
)
),
...branches
...branches!
.filter(b => b.remote)
.map(b =>
BranchQuickPickItem.create(
Expand Down
4 changes: 3 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ export enum StatusBarCommand {

export enum TagSorting {
NameDesc = 'name:desc',
NameAsc = 'name:asc'
NameAsc = 'name:asc',
DateDesc = 'date:desc',
DateAsc = 'date:asc'
}

export enum ViewBranchesLayout {
Expand Down
6 changes: 3 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ async function migrateSettings(context: ExtensionContext, previousVersion: strin
}

function notifyOnUnsupportedGitVersion(version: string) {
if (GitService.compareGitVersion('2.2.0') !== -1) return;
if (GitService.compareGitVersion('2.7.2') !== -1) return;

// If git is less than v2.2.0
void Messages.showGitVersionUnsupportedErrorMessage(version);
// If git is less than v2.7.2
void Messages.showGitVersionUnsupportedErrorMessage(version, '2.7.2');
}

async function showWelcomeOrWhatsNew(version: string, previousVersion: string | undefined) {
Expand Down
4 changes: 2 additions & 2 deletions src/git/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Logger } from '../logger';
import { Objects, Strings } from '../system';
import { findGitPath, GitLocation } from './locator';
import { run, RunOptions } from './shell';
import { GitBranchParser, GitLogParser, GitReflogParser, GitStashParser } from './parsers/parsers';
import { GitBranchParser, GitLogParser, GitReflogParser, GitStashParser, GitTagParser } from './parsers/parsers';
import { GitFileStatus } from './models/file';

export * from './models/models';
Expand Down Expand Up @@ -1156,6 +1156,6 @@ export namespace Git {
}

export function tag(repoPath: string) {
return git<string>({ cwd: repoPath }, 'tag', '-l', '-n1');
return git<string>({ cwd: repoPath }, 'tag', '-l', `--format=${GitTagParser.defaultFormat}`);
}
}
25 changes: 2 additions & 23 deletions src/git/gitService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ export class GitService implements Disposable {

private readonly _branchesCache = new Map<string, GitBranch[]>();
private readonly _tagsCache = new Map<string, GitTag[]>();
private readonly _tagsWithRefsCache = new Map<string, GitTag[]>();
private readonly _trackedCache = new Map<string, boolean | Promise<boolean>>();
private readonly _userMapCache = new Map<string, { name?: string; email?: string } | null>();

Expand All @@ -198,7 +197,6 @@ export class GitService implements Disposable {
this._repositoryTree.forEach(r => r.dispose());
this._branchesCache.clear();
this._tagsCache.clear();
this._tagsWithRefsCache.clear();
this._trackedCache.clear();
this._userMapCache.clear();

Expand Down Expand Up @@ -230,7 +228,6 @@ export class GitService implements Disposable {

this._branchesCache.delete(repo.path);
this._tagsCache.delete(repo.path);
this._tagsWithRefsCache.clear();
this._trackedCache.clear();

if (e.changed(RepositoryChange.Config)) {
Expand Down Expand Up @@ -1176,10 +1173,7 @@ export class GitService implements Disposable {

@log()
async getBranchesAndTagsTipsFn(repoPath: string | undefined, currentName?: string) {
const [branches, tags] = await Promise.all([
this.getBranches(repoPath),
this.getTags(repoPath, { includeRefs: true })
]);
const [branches, tags] = await Promise.all([this.getBranches(repoPath), this.getTags(repoPath)]);

const branchesAndTagsBySha = Arrays.groupByFilterMap(
(branches as { name: string; sha: string }[]).concat(tags as { name: string; sha: string }[]),
Expand Down Expand Up @@ -2475,27 +2469,12 @@ export class GitService implements Disposable {
@log()
async getTags(
repoPath: string | undefined,
options: { filter?: (t: GitTag) => boolean; includeRefs?: boolean; sort?: boolean } = {}
options: { filter?: (t: GitTag) => boolean; sort?: boolean } = {}
): Promise<GitTag[]> {
if (repoPath === undefined) return [];

let tags: GitTag[] | undefined;
try {
if (options.includeRefs) {
tags = this._tagsWithRefsCache.get(repoPath);
if (tags !== undefined) return tags;

const data = await Git.show_ref__tags(repoPath);
tags = GitTagParser.parseWithRef(data, repoPath) || [];

const repo = await this.getRepository(repoPath);
if (repo !== undefined && repo.supportsChangeEvents) {
this._tagsWithRefsCache.set(repoPath, tags);
}

return tags;
}

tags = this._tagsCache.get(repoPath);
if (tags !== undefined) return tags;

Expand Down
2 changes: 1 addition & 1 deletion src/git/models/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ export class Repository implements Disposable {
return Container.git.getStatusForRepo(this.path);
}

getTags(options?: { filter?: (t: GitTag) => boolean; includeRefs?: boolean; sort?: boolean }): Promise<GitTag[]> {
getTags(options?: { filter?: (t: GitTag) => boolean; sort?: boolean }): Promise<GitTag[]> {
return Container.git.getTags(this.path, options);
}

Expand Down

0 comments on commit 358fa90

Please sign in to comment.