diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3893573..a5df830 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,20 +6,27 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [7.0.0-beta2] - 2017-12-16
### Added
-- Adds a new `Active Repository` node to `Repository View` of the `GitLens` view -- closes [#224](https://github.com/eamodio/vscode-gitlens/issues/224)
+- Adds a new `Active Repository` node to the `Repository View` of the `GitLens` view -- closes [#224](https://github.com/eamodio/vscode-gitlens/issues/224)
- Automatically updates to track the repository of the active editor
- Only visible if there is more than 1 repository within the workspace
+
+- Adds a new `Tags` node to the `Repository View` of the `GitLens` view
+ - Provides a list of tags
+ - Expand each tag to easily see its revision (commit) history
+ - Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
+ - Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, `Compare with Selected`, `Select for Compare`, `Rebase Commit (via Terminal)`, `Reset Commit (via Terminal)`, and `Refresh` commands
+ - Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands
+ - Provides a context menu on each tag with `Compare with Selected`, `Select for Compare`, and `Refresh` commands
+ - Provides a context menu with a `Refresh` command
+
- Adds [Gravatar](https://en.gravatar.com/) support to the `GitLens` view
- Adds `gitlens.gitExplorer.gravatars` setting to specify whether or not to show gravatar images instead of commit (or status) icons in the `GitLens` view
- Adds `gitlens.gitExplorer.gravatarsDefault` setting to specify the style of the gravatar default (fallback) images in the `GitLens` view `identicon` - a geometric pattern `mm` - (mystery-man) a simple, cartoon-style silhouetted outline of a person (does not vary by email hash) `monsterid` - a monster with different colors, faces, etc `retro` - 8-bit arcade-style pixelated faces `robohash` - a robot with different colors, faces, etc `wavatar` - faces with differing features and backgrounds
- Adds `gitlens.resultsExplorer.gravatars` setting to specify whether or not to show gravatar images instead of commit (or status) icons in the `GitLens Results` view
- Adds `gitlens.resultsExplorer.gravatarsDefault` setting to specify the style of the gravatar default (fallback) images in the `GitLens Results` view `identicon` - a geometric pattern `mm` - (mystery-man) a simple, cartoon-style silhouetted outline of a person (does not vary by email hash) `monsterid` - a monster with different colors, faces, etc `retro` - 8-bit arcade-style pixelated faces `robohash` - a robot with different colors, faces, etc `wavatar` - faces with differing features and backgrounds
-- Adds `Select for Compare` command (`gitlens.explorers.selectForCompare`) to branch and revision (commit) nodes in the `GitLens` view to mark the base revision of a comparision
-- Adds `Compare with Selected` command (`gitlens.explorers.compareWithSelected`) to branch and revision (commit) nodes in the `GitLens` view once another branch or revision (commit) node within the same repository has been selected to compare the current selection with the previously selected revision (branch or commit)
-- Adds `Apply Changes` option to the commit/stash file quick pick menu -- closes [#232](https://github.com/eamodio/vscode-gitlens/issues/232)
-- Adds `Show All Commits` option to the commit search quick pick menu to show all the results, if there are more than the threshold
-- Adds `Show in Results` option to the commit search quick pick menu to show the results in the `GitLens Results` view
-- Adds `Show in Results` option to the file history quick pick menu to show the history in the `GitLens Results` view
+
+- Adds `Select for Compare` command (`gitlens.explorers.selectForCompare`) to branch, remote branch, tag, and revision (commit) nodes in the `GitLens` view to mark the base reference of a comparision
+- Adds `Compare with Selected` command (`gitlens.explorers.compareWithSelected`) to branch, remote branch, tag, and revision (commit) nodes in the `GitLens` view once another reference within the same repository has been selected to compare the current selection with the previously selected reference in the `GitLens Results` view
- Adds an all-new, on-demand `GitLens Results` view to the Explorer activity
@@ -39,6 +46,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Provides toolbar commands to `Search Commits`, `Keep Results`, `Refresh`, `Show Files in Automatic View` or `Show Files in List View` or `Show Files in Tree View`, and `Close`
+- Adds `Apply Changes` option to the commit/stash file quick pick menu -- closes [#232](https://github.com/eamodio/vscode-gitlens/issues/232)
+- Adds `Show All Commits` option to the commit search quick pick menu to show all the results, if there are more than the threshold
+- Adds `Show in Results` option to the commit search quick pick menu to show the results in the `GitLens Results` view
+- Adds `Show in Results` option to the file history quick pick menu to show the history in the `GitLens Results` view
+
+### Changed
+- Improves startup performance a bit
+
### Fixed
- Fixes [#228](https://github.com/eamodio/vscode-gitlens/issues/228) - Gutter blame spills over heatmap
- Fixes incorrect blame highlighting -- thanks to [PR #231](https://github.com/eamodio/vscode-gitlens/pull/231) by Alexey Vasyukov ([@notmedia](https://github.com/notmedia))!
diff --git a/README.md b/README.md
index dada21b..99af2da 100644
--- a/README.md
+++ b/README.md
@@ -160,7 +160,7 @@ While GitLens is highly customizable and provides many [configuration settings](
- Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
- Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, `Compare with Selected`, `Select for Compare`, `Rebase Commit (via Terminal)`, `Reset Commit (via Terminal)`, and `Refresh` commands
- Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands
- - Provides a context menu on each branch with `Open Branch in Remote`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Rebase Branch to Remote (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands
+ - Provides a context menu on each branch with `Open Branch in Remote`, `Compare with Selected`, `Select for Compare`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Rebase Branch to Remote (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands
- Provides a context menu with `Open Branches in Remote`, and `Refresh` commands
- `Remotes` node — provides a list of remotes
@@ -170,7 +170,7 @@ While GitLens is highly customizable and provides many [configuration settings](
- Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
- Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`,`Show Commit Details`, `Compare with Selected`, `Select for Compare`, and `Refresh` commands
- Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, `Show File History`, and `Show Commit File Details` commands
- - Provides a context menu on each remote branch with `Open Branch in Remote`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands
+ - Provides a context menu on each remote branch with `Open Branch in Remote`, `Compare with Selected`, `Select for Compare`, `Checkout Branch (via Terminal)`, `Create Branch (via Terminal)...`, `Delete Branch (via Terminal)`, `Squash Branch into Commit (via Terminal)`, and `Refresh` commands
- Provides a context menu on each remote with `Open Branches in Remote`, `Open Repository in Remote`, `Remove Remote (via Terminal)`, and `Refresh` commands
- Provides a context menu with a `Refresh` command
@@ -180,6 +180,14 @@ While GitLens is highly customizable and provides many [configuration settings](
- Provides a context menu on each stashed file with `Apply Changes`, `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, and `Show File History` commands
- Provides a context menu with `Stash Changes`, and `Refresh` commands
+ - `Tags` node — provides a list of tags
+ - Expand each tag to easily see its revision (commit) history
+ - Expand each revision (commit) to quickly see the set of files changed, complete with status indicators for adds, changes, renames, and deletes
+ - Provides a context menu on each revision (commit) with `Open Commit in Remote`, `Open All Changes`, `Open All Changes with Working Tree`, `Open Files`, `Open Revisions`, `Copy Commit ID to Clipboard`, `Copy Commit Message to Clipboard`, `Show Commit Details`, `Compare with Selected`, `Select for Compare`, `Rebase Commit (via Terminal)`, `Reset Commit (via Terminal)`, and `Refresh` commands
+ - Provides a context menu on each changed file with `Open Changes`, `Open Changes with Working Tree`, `Open File`, `Open Revision`, `Open File in Remote`, `Open Revision in Remote`, `Apply Changes`, and `Show Commit File Details` commands
+ - Provides a context menu on each tag with `Compare with Selected`, `Select for Compare`, and `Refresh` commands
+ - Provides a context menu with a `Refresh` command
+
- `History View` - provides the revision history of the active file
![GitLens History view](https://raw.githubusercontent.com/eamodio/vscode-gitlens/master/images/screenshot-git-custom-view-history.png)
diff --git a/images/dark/icon-tag.svg b/images/dark/icon-tag.svg
new file mode 100644
index 0000000..6c42495
--- /dev/null
+++ b/images/dark/icon-tag.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/images/light/icon-tag.svg b/images/light/icon-tag.svg
new file mode 100644
index 0000000..0a65404
--- /dev/null
+++ b/images/light/icon-tag.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
index 6a4e0b6..323c356 100644
--- a/package.json
+++ b/package.json
@@ -2672,6 +2672,16 @@
"group": "8_gitlens@1"
},
{
+ "command": "gitlens.explorers.compareWithSelected",
+ "when": "viewItem == gitlens:tag && gitlens:explorers:canCompare",
+ "group": "7_gitlens@1"
+ },
+ {
+ "command": "gitlens.explorers.selectForCompare",
+ "when": "viewItem == gitlens:tag",
+ "group": "7_gitlens@2"
+ },
+ {
"command": "gitlens.gitExplorer.refreshNode",
"when": "view == gitlens.gitExplorer && viewItem != gitlens:commit-file && viewItem != gitlens:stash-file && viewItem != gitlens:status-file",
"group": "9_gitlens@1"
diff --git a/src/git/git.ts b/src/git/git.ts
index 1531f45..c9023c6 100644
--- a/src/git/git.ts
+++ b/src/git/git.ts
@@ -19,6 +19,7 @@ export * from './parsers/logParser';
export * from './parsers/remoteParser';
export * from './parsers/stashParser';
export * from './parsers/statusParser';
+export * from './parsers/tagParser';
export * from './remotes/provider';
let git: IGit;
@@ -147,15 +148,15 @@ export class Git {
return git;
}
- static async getVersionedFile(repoPath: string | undefined, fileName: string, branchOrSha: string) {
- const data = await Git.show(repoPath, fileName, branchOrSha, { encoding: 'binary' });
+ static async getVersionedFile(repoPath: string | undefined, fileName: string, ref: string) {
+ const data = await Git.show(repoPath, fileName, ref, { encoding: 'binary' });
if (data === undefined) return undefined;
- if (Git.isStagedUncommitted(branchOrSha)) {
- branchOrSha = '';
+ if (Git.isStagedUncommitted(ref)) {
+ ref = '';
}
- const suffix = Strings.truncate(Strings.sanitizeForFileSystem(Git.isSha(branchOrSha) ? Git.shortenSha(branchOrSha) : branchOrSha), 50, '');
+ const suffix = Strings.truncate(Strings.sanitizeForFileSystem(Git.isSha(ref) ? Git.shortenSha(ref) : ref), 50, '');
const ext = path.extname(fileName);
return new Promise((resolve, reject) => {
tmp.file({ prefix: `${path.basename(fileName, ext)}-${suffix}__`, postfix: ext },
@@ -165,7 +166,7 @@ export class Git {
return;
}
- Logger.log(`getVersionedFile[${destination}]('${repoPath}', '${fileName}', ${branchOrSha})`);
+ Logger.log(`getVersionedFile[${destination}]('${repoPath}', '${fileName}', ${ref})`);
fs.appendFile(destination, data, { encoding: 'binary' }, err => {
if (err) {
reject(err);
@@ -330,10 +331,10 @@ export class Git {
return gitCommand({ cwd: repoPath }, ...params);
}
- static difftool_dirDiff(repoPath: string, tool: string, sha1: string, sha2?: string) {
- const params = [`difftool`, `--dir-diff`, `--tool=${tool}`, sha1];
- if (sha2) {
- params.push(sha2);
+ static difftool_dirDiff(repoPath: string, tool: string, ref1: string, ref2?: string) {
+ const params = [`difftool`, `--dir-diff`, `--tool=${tool}`, ref1];
+ if (ref2) {
+ params.push(ref2);
}
return gitCommand({ cwd: repoPath }, ...params);
@@ -503,18 +504,18 @@ export class Git {
}
}
- static async show(repoPath: string | undefined, fileName: string, branchOrSha: string, options: { encoding?: string } = {}) {
+ static async show(repoPath: string | undefined, fileName: string, ref: string, options: { encoding?: string } = {}) {
const [file, root] = Git.splitPath(fileName, repoPath);
- if (Git.isStagedUncommitted(branchOrSha)) {
- branchOrSha = ':';
+ if (Git.isStagedUncommitted(ref)) {
+ ref = ':';
}
- if (Git.isUncommitted(branchOrSha)) throw new Error(`sha=${branchOrSha} is uncommitted`);
+ if (Git.isUncommitted(ref)) throw new Error(`sha=${ref} is uncommitted`);
const opts = { cwd: root, encoding: options.encoding || 'utf8', willHandleErrors: true } as GitCommandOptions;
- const args = branchOrSha.endsWith(':')
- ? `${branchOrSha}./${file}`
- : `${branchOrSha}:./${file}`;
+ const args = ref.endsWith(':')
+ ? `${ref}./${file}`
+ : `${ref}:./${file}`;
try {
const data = await gitCommand(opts, 'show', args);
@@ -573,4 +574,10 @@ export class Git {
const porcelain = porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain';
return gitCommand({ cwd: root, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' } }, 'status', porcelain, file);
}
+
+ static tag(repoPath: string) {
+ const params = [`tag`, `-l`];
+
+ return gitCommand({ cwd: repoPath }, ...params);
+ }
}
\ No newline at end of file
diff --git a/src/git/models/models.ts b/src/git/models/models.ts
index 1ebb99c..5de9860 100644
--- a/src/git/models/models.ts
+++ b/src/git/models/models.ts
@@ -10,4 +10,5 @@ export * from './remote';
export * from './repository';
export * from './stash';
export * from './stashCommit';
-export * from './status';
\ No newline at end of file
+export * from './status';
+export * from './tag';
\ No newline at end of file
diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts
index 05fea1c..90e9639 100644
--- a/src/git/models/repository.ts
+++ b/src/git/models/repository.ts
@@ -2,7 +2,7 @@
import { Functions } from '../../system';
import { ConfigurationChangeEvent, Disposable, Event, EventEmitter, RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode';
import { configuration, IRemotesConfig } from '../../configuration';
-import { GitBranch, GitDiffShortStat, GitRemote, GitStash, GitStatus } from '../git';
+import { GitBranch, GitDiffShortStat, GitRemote, GitStash, GitStatus, GitTag } from '../git';
import { GitService, GitUri } from '../../gitService';
import { RemoteProviderFactory, RemoteProviderMap } from '../remotes/factory';
import * as _path from 'path';
@@ -237,11 +237,11 @@ export class Repository extends Disposable {
return this._branch;
}
- async getBranches(): Promise {
+ getBranches(): Promise {
return this.git.getBranches(this.path);
}
- async getChangedFilesCount(sha?: string): Promise {
+ getChangedFilesCount(sha?: string): Promise {
return this.git.getChangedFilesCount(this.path, sha);
}
@@ -258,14 +258,18 @@ export class Repository extends Disposable {
return this._remotes;
}
- async getStashList(): Promise {
+ getStashList(): Promise {
return this.git.getStashList(this.path);
}
- async getStatus(): Promise {
+ getStatus(): Promise {
return this.git.getStatusForRepo(this.path);
}
+ getTags(): Promise {
+ return this.git.getTags(this.path);
+ }
+
async hasRemote(): Promise {
const branch = await this.getBranch();
return branch !== undefined && branch.tracking !== undefined;
diff --git a/src/git/models/tag.ts b/src/git/models/tag.ts
new file mode 100644
index 0000000..62e275b
--- /dev/null
+++ b/src/git/models/tag.ts
@@ -0,0 +1,9 @@
+'use strict';
+
+export class GitTag {
+
+ constructor(
+ public readonly repoPath: string,
+ public readonly name: string
+ ) { }
+}
\ No newline at end of file
diff --git a/src/git/parsers/tagParser.ts b/src/git/parsers/tagParser.ts
new file mode 100644
index 0000000..c39e6c9
--- /dev/null
+++ b/src/git/parsers/tagParser.ts
@@ -0,0 +1,15 @@
+'use strict';
+import { Arrays } from '../../system';
+import { GitTag } from './../git';
+
+export class GitTagParser {
+
+ static parse(data: string, repoPath: string): GitTag[] | undefined {
+ if (!data) return undefined;
+
+ const tags = Arrays.filterMap(data.split('\n'), t => !!t ? new GitTag(repoPath, t) : undefined);
+ if (!tags.length) return undefined;
+
+ return tags;
+ }
+}
\ No newline at end of file
diff --git a/src/gitService.ts b/src/gitService.ts
index 6d7da36..e0369c9 100644
--- a/src/gitService.ts
+++ b/src/gitService.ts
@@ -4,7 +4,7 @@ import { ConfigurationChangeEvent, Disposable, Event, EventEmitter, Range, TextD
import { configuration, IConfig, IRemotesConfig } from './configuration';
import { CommandContext, DocumentSchemes, setCommandContext } from './constants';
import { RemoteProviderFactory, RemoteProviderMap } from './git/remotes/factory';
-import { Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitBranchParser, GitCommit, GitCommitType, GitDiff, GitDiffChunkLine, GitDiffParser, GitDiffShortStat, GitLog, GitLogCommit, GitLogParser, GitRemote, GitRemoteParser, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, IGit, Repository } from './git/git';
+import { Git, GitAuthor, GitBlame, GitBlameCommit, GitBlameLine, GitBlameLines, GitBlameParser, GitBranch, GitBranchParser, GitCommit, GitCommitType, GitDiff, GitDiffChunkLine, GitDiffParser, GitDiffShortStat, GitLog, GitLogCommit, GitLogParser, GitRemote, GitRemoteParser, GitStash, GitStashParser, GitStatus, GitStatusFile, GitStatusParser, GitTag, GitTagParser, IGit, Repository } from './git/git';
import { GitUri, IGitCommitInfo } from './git/gitUri';
import { Logger } from './logger';
import * as fs from 'fs';
@@ -1197,6 +1197,15 @@ export class GitService extends Disposable {
return status;
}
+ async getTags(repoPath: string | undefined): Promise {
+ if (repoPath === undefined) return [];
+
+ Logger.log(`getTags('${repoPath}')`);
+
+ const data = await Git.tag(repoPath);
+ return GitTagParser.parse(data, repoPath) || [];
+ }
+
async getVersionedFile(repoPath: string | undefined, fileName: string, sha: string | undefined) {
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', '${sha}')`);
diff --git a/src/views/explorerNode.ts b/src/views/explorerNode.ts
index e07ce36..d85eea9 100644
--- a/src/views/explorerNode.ts
+++ b/src/views/explorerNode.ts
@@ -48,7 +48,9 @@ export enum ResourceType {
StatusFile = 'gitlens:status-file',
StatusFiles = 'gitlens:status-files',
StatusFileCommits = 'gitlens:status-file-commits',
- StatusUpstream = 'gitlens:status-upstream'
+ StatusUpstream = 'gitlens:status-upstream',
+ Tag = 'gitlens:tag',
+ Tags = 'gitlens:tags'
}
export type Explorer = GitExplorer | ResultsExplorer;
diff --git a/src/views/explorerNodes.ts b/src/views/explorerNodes.ts
index ae8485c..96fca7d 100644
--- a/src/views/explorerNodes.ts
+++ b/src/views/explorerNodes.ts
@@ -23,4 +23,6 @@ export * from './statusFileNode';
export * from './statusFilesNode';
export * from './statusFilesResultsNode';
export * from './statusNode';
-export * from './statusUpstreamNode';
\ No newline at end of file
+export * from './statusUpstreamNode';
+export * from './tagsNode';
+export * from './tagNode';
\ No newline at end of file
diff --git a/src/views/repositoryNode.ts b/src/views/repositoryNode.ts
index b642cc6..73cae60 100644
--- a/src/views/repositoryNode.ts
+++ b/src/views/repositoryNode.ts
@@ -6,10 +6,11 @@ import { GlyphChars } from '../constants';
import { ExplorerNode, ResourceType } from './explorerNode';
import { GitExplorer } from './gitExplorer';
import { GitUri, Repository, RepositoryChange, RepositoryChangeEvent } from '../gitService';
+import { Logger } from '../logger';
import { RemotesNode } from './remotesNode';
import { StatusNode } from './statusNode';
import { StashesNode } from './stashesNode';
-import { Logger } from '../logger';
+import { TagsNode } from './tagsNode';
export class RepositoryNode extends ExplorerNode {
@@ -30,7 +31,8 @@ export class RepositoryNode extends ExplorerNode {
new StatusNode(this.uri, this.repo, this.explorer, this.active),
new BranchesNode(this.uri, this.repo, this.explorer, this.active),
new RemotesNode(this.uri, this.repo, this.explorer),
- new StashesNode(this.uri, this.repo, this.explorer)
+ new StashesNode(this.uri, this.repo, this.explorer),
+ new TagsNode(this.uri, this.repo, this.explorer)
];
return this.children;
}
diff --git a/src/views/tagNode.ts b/src/views/tagNode.ts
new file mode 100644
index 0000000..79fe6b0
--- /dev/null
+++ b/src/views/tagNode.ts
@@ -0,0 +1,46 @@
+'use strict';
+import { Iterables } from '../system';
+import { TreeItem, TreeItemCollapsibleState } from 'vscode';
+import { CommitNode } from './commitNode';
+import { Explorer, ExplorerNode, ExplorerRefNode, MessageNode, ResourceType, ShowAllNode } from './explorerNode';
+import { GitTag, GitUri } from '../gitService';
+
+export class TagNode extends ExplorerRefNode {
+
+ readonly supportsPaging: boolean = true;
+
+ constructor(
+ public readonly tag: GitTag,
+ uri: GitUri,
+ private readonly explorer: Explorer
+ ) {
+ super(uri);
+ }
+
+ get ref(): string {
+ return this.tag.name;
+ }
+
+ async getChildren(): Promise {
+ const log = await this.explorer.git.getLogForRepo(this.uri.repoPath!, { maxCount: this.maxCount, ref: this.tag.name });
+ if (log === undefined) return [new MessageNode('No commits yet')];
+
+ const children: (CommitNode | ShowAllNode)[] = [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.explorer))];
+ if (log.truncated) {
+ children.push(new ShowAllNode('Show All Commits', this, this.explorer));
+ }
+ return children;
+ }
+
+ async getTreeItem(): Promise {
+ const item = new TreeItem(this.tag.name, TreeItemCollapsibleState.Collapsed);
+ item.contextValue = ResourceType.Tag;
+
+ item.iconPath = {
+ dark: this.explorer.context.asAbsolutePath(`images/dark/icon-tag.svg`),
+ light: this.explorer.context.asAbsolutePath(`images/light/icon-tag.svg`)
+ };
+
+ return item;
+ }
+}
diff --git a/src/views/tagsNode.ts b/src/views/tagsNode.ts
new file mode 100644
index 0000000..2b5deca
--- /dev/null
+++ b/src/views/tagsNode.ts
@@ -0,0 +1,36 @@
+'use strict';
+import { TreeItem, TreeItemCollapsibleState } from 'vscode';
+import { Explorer, ExplorerNode, MessageNode, ResourceType } from './explorerNode';
+import { GitUri, Repository } from '../gitService';
+import { TagNode } from './tagNode';
+
+export class TagsNode extends ExplorerNode {
+
+ constructor(
+ uri: GitUri,
+ private readonly repo: Repository,
+ private readonly explorer: Explorer
+ ) {
+ super(uri);
+ }
+
+ async getChildren(): Promise {
+ const tags = await this.repo.getTags();
+ if (tags.length === 0) return [new MessageNode('No tags yet')];
+
+ tags.sort((a, b) => a.name.localeCompare(b.name));
+ return [...tags.map(t => new TagNode(t, this.uri, this.explorer))];
+ }
+
+ async getTreeItem(): Promise {
+ const item = new TreeItem(`Tags`, TreeItemCollapsibleState.Collapsed);
+ item.contextValue = ResourceType.Tags;
+
+ item.iconPath = {
+ dark: this.explorer.context.asAbsolutePath('images/dark/icon-tag.svg'),
+ light: this.explorer.context.asAbsolutePath('images/light/icon-tag.svg')
+ };
+
+ return item;
+ }
+ }