Skip to content

Commit

Permalink
Adds caching to stashes & contributors
Browse files Browse the repository at this point in the history
  • Loading branch information
eamodio committed Dec 31, 2020
1 parent bbbbc01 commit e7ddef7
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [Unreleased]

### Changes

- Improves the performance of the _Stashes_ and _Contributors_ views

### Fixed

- Fixes [#1294](https://github.com/eamodio/vscode-gitlens/issues/1294) - Error when open commits list
Expand Down
89 changes: 61 additions & 28 deletions src/git/gitService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ export class GitService implements Disposable {
private _repositoriesLoadingPromise: Promise<void> | undefined;

private readonly _branchesCache = new Map<string, GitBranch[]>();
private readonly _contributorsCache = new Map<string, GitContributor[]>();
private readonly _remotesWithApiProviderCache = new Map<string, GitRemote<RichRemoteProvider> | null>();
private readonly _stashesCache = new Map<string, GitStash | null>();
private readonly _tagsCache = 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 Down Expand Up @@ -157,7 +159,9 @@ export class GitService implements Disposable {
dispose() {
this._repositoryTree.forEach(r => r.dispose());
this._branchesCache.clear();
this._contributorsCache.clear();
this._remotesWithApiProviderCache.clear();
this._stashesCache.clear();
this._tagsCache.clear();
this._trackedCache.clear();
this._userMapCache.clear();
Expand Down Expand Up @@ -186,12 +190,20 @@ export class GitService implements Disposable {
}

private onAnyRepositoryChanged(repo: Repository, e: RepositoryChangeEvent) {
if (e.changed(RepositoryChange.Stash, true)) return;
if (e.changed(RepositoryChange.Stash, true)) {
this._stashesCache.delete(repo.path);

return;
}

this._branchesCache.delete(repo.path);
this._contributorsCache.delete(repo.path);
if (e.changed(RepositoryChange.Remotes)) {
this._remotesWithApiProviderCache.clear();
}
if (e.changed(RepositoryChange.Stash)) {
this._stashesCache.delete(repo.path);
}
this._tagsCache.delete(repo.path);
this._trackedCache.clear();

Expand Down Expand Up @@ -1393,31 +1405,43 @@ export class GitService implements Disposable {
async getContributors(repoPath: string): Promise<GitContributor[]> {
if (repoPath == null) return [];

try {
const data = await Git.shortlog(repoPath);
const shortlog = GitShortLogParser.parse(data, repoPath);
if (shortlog == null) return [];

// Mark the current user
const currentUser = await Container.git.getCurrentUser(repoPath);
if (currentUser != null) {
const index = shortlog.contributors.findIndex(
c => currentUser.email === c.email && currentUser.name === c.name,
);
if (index !== -1) {
const c = shortlog.contributors[index];
shortlog.contributors.splice(
index,
1,
new GitContributor(c.repoPath, c.name, c.email, c.count, true),
);
let contributors = this.useCaching ? this._contributorsCache.get(repoPath) : undefined;
if (contributors == null) {
try {
const data = await Git.shortlog(repoPath);
const shortlog = GitShortLogParser.parse(data, repoPath);
if (shortlog != null) {
// Mark the current user
const currentUser = await Container.git.getCurrentUser(repoPath);
if (currentUser != null) {
const index = shortlog.contributors.findIndex(
c => currentUser.email === c.email && currentUser.name === c.name,
);
if (index !== -1) {
const c = shortlog.contributors[index];
shortlog.contributors.splice(
index,
1,
new GitContributor(c.repoPath, c.name, c.email, c.count, true),
);
}
}

contributors = shortlog.contributors;
} else {
contributors = [];
}
}

return shortlog.contributors;
} catch (ex) {
return [];
const repo = await this.getRepository(repoPath);
if (repo?.supportsChangeEvents) {
this._contributorsCache.set(repoPath, contributors);
}
} catch (ex) {
return [];
}
}

return contributors;
}

@log()
Expand Down Expand Up @@ -3236,11 +3260,20 @@ export class GitService implements Disposable {
async getStash(repoPath: string | undefined): Promise<GitStash | undefined> {
if (repoPath == null) return undefined;

const data = await Git.stash__list(repoPath, {
similarityThreshold: Container.config.advanced.similarityThreshold,
});
const stash = GitStashParser.parse(data, repoPath);
return stash;
let stash = this.useCaching ? this._stashesCache.get(repoPath) : undefined;
if (stash === undefined) {
const data = await Git.stash__list(repoPath, {
similarityThreshold: Container.config.advanced.similarityThreshold,
});
stash = GitStashParser.parse(data, repoPath);

const repo = await this.getRepository(repoPath);
if (repo?.supportsChangeEvents) {
this._stashesCache.set(repoPath, stash ?? null);
}
}

return stash ?? undefined;
}

@log()
Expand Down
7 changes: 7 additions & 0 deletions src/views/branchesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ export class BranchesViewNode extends ViewNode<BranchesView> {
const [child] = this.children;

const branches = await child.repo.getBranches({ filter: b => !b.remote });
if (branches.length === 0) {
this.view.message = 'No branches could be found.';

return [];
}

this.view.message = undefined;
this.view.title = `Branches (${branches.length})`;

return child.getChildren();
Expand Down
7 changes: 7 additions & 0 deletions src/views/contributorsView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ export class ContributorsViewNode extends ViewNode<ContributorsView> {
const [child] = this.children;

const contributors = await child.repo.getContributors();
if (contributors.length === 0) {
this.view.message = 'No contributors could be found.';

return [];
}

this.view.message = undefined;
this.view.title = `Contributors (${contributors.length})`;

return child.getChildren();
Expand Down
2 changes: 1 addition & 1 deletion src/views/nodes/remotesNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class RemotesNode extends ViewNode<RemotesView | RepositoriesView> {
async getChildren(): Promise<ViewNode[]> {
if (this._children == null) {
const remotes = await this.repo.getRemotes({ sort: true });
if (remotes == null || remotes.length === 0) {
if (remotes.length === 0) {
return [new MessageNode(this.view, this, 'No remotes could be found')];
}

Expand Down
2 changes: 1 addition & 1 deletion src/views/nodes/stashesNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class StashesNode extends ViewNode<StashesView | RepositoriesView> {
async getChildren(): Promise<ViewNode[]> {
if (this._children == null) {
const stash = await this.repo.getStash();
if (stash === undefined) return [new MessageNode(this.view, this, 'No stashes could be found.')];
if (stash == null) return [new MessageNode(this.view, this, 'No stashes could be found.')];

this._children = [...Iterables.map(stash.commits.values(), c => new StashNode(this.view, this, c))];
}
Expand Down
7 changes: 7 additions & 0 deletions src/views/remotesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ export class RemotesViewNode extends ViewNode<RemotesView> {
const [child] = this.children;

const remotes = await child.repo.getRemotes();
if (remotes.length === 0) {
this.view.message = 'No remotes could be found.';

return [];
}

this.view.message = undefined;
this.view.title = `Remotes (${remotes.length})`;

return child.getChildren();
Expand Down
7 changes: 7 additions & 0 deletions src/views/stashesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ export class StashesViewNode extends ViewNode<StashesView> {
const [child] = this.children;

const stash = await child.repo.getStash();
if (stash == null) {
this.view.message = 'No stashes could be found.';

return [];
}

this.view.message = undefined;
this.view.title = `Stashes (${stash?.commits.size ?? 0})`;

return child.getChildren();
Expand Down
7 changes: 7 additions & 0 deletions src/views/tagsView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ export class TagsViewNode extends ViewNode<TagsView> {
const [child] = this.children;

const tags = await child.repo.getTags();
if (tags.length === 0) {
this.view.message = 'No tags could be found.';

return [];
}

this.view.message = undefined;
this.view.title = `Tags (${tags.length})`;

return child.getChildren();
Expand Down

0 comments on commit e7ddef7

Please sign in to comment.