Skip to content

Commit

Permalink
mhutchie#287 Added a new "Only follow the first parent of commits" op…
Browse files Browse the repository at this point in the history
…tion to the Git Graph View's Repository Settings Widget. The default value can be defined globally for all repositories using the new Extension Setting "git-graph.onlyFollowFirstParent".
  • Loading branch information
mhutchie committed Apr 19, 2020
1 parent abec526 commit 414545a
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 36 deletions.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,11 @@
"default": true,
"description": "Display merge commits with a muted text color."
},
"git-graph.onlyFollowFirstParent": {
"type": "boolean",
"default": false,
"markdownDescription": "Only follow the first parent of commits when discovering the commits to load in the Git Graph View. See [--first-parent](https://git-scm.com/docs/git-log#Documentation/git-log.txt---first-parent) to find out more about this setting."
},
"git-graph.openDiffTabLocation": {
"type": "string",
"enum": [
Expand Down
7 changes: 7 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,13 @@ class Config {
return !!this.config.get('muteMergeCommits', true);
}

/**
* Get the value of the `git-graph.onlyFollowFirstParent` Extension Setting.
*/
get onlyFollowFirstParent() {
return !!this.config.get('onlyFollowFirstParent', false);
}

/**
* Get the value of the `git-graph.openDiffTabLocation` Extension Setting.
*/
Expand Down
9 changes: 6 additions & 3 deletions src/dataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,16 @@ export class DataSource implements vscode.Disposable {
* @param showTags Are tags are shown.
* @param showRemoteBranches Are remote branches shown.
* @param includeCommitsMentionedByReflogs Should commits mentioned by reflogs being included.
* @param onlyFollowFirstParent Only follow the first parent of commits.
* @param remotes An array of known remotes.
* @param hideRemotes An array of hidden remotes.
* @param stashes An array of all stashes in the repository.
* @returns The commits in the repository.
*/
public getCommits(repo: string, branches: string[] | null, maxCommits: number, showTags: boolean, showRemoteBranches: boolean, includeCommitsMentionedByReflogs: boolean, remotes: string[], hideRemotes: string[], stashes: ReadonlyArray<GitStash>): Promise<GitCommitData> {
public getCommits(repo: string, branches: string[] | null, maxCommits: number, showTags: boolean, showRemoteBranches: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, remotes: string[], hideRemotes: string[], stashes: ReadonlyArray<GitStash>): Promise<GitCommitData> {
const config = getConfig();
return Promise.all([
this.getLog(repo, branches, maxCommits + 1, showTags && config.showCommitsOnlyReferencedByTags, showRemoteBranches, includeCommitsMentionedByReflogs, config.commitOrdering, remotes, hideRemotes, stashes),
this.getLog(repo, branches, maxCommits + 1, showTags && config.showCommitsOnlyReferencedByTags, showRemoteBranches, includeCommitsMentionedByReflogs, onlyFollowFirstParent, config.commitOrdering, remotes, hideRemotes, stashes),
this.getRefs(repo, showRemoteBranches, hideRemotes).then((refData: GitRefData) => refData, (errorMessage: string) => errorMessage)
]).then(async (results) => {
let commits: GitCommitRecord[] = results[0], refData: GitRefData | string = results[1], i;
Expand Down Expand Up @@ -1173,14 +1174,16 @@ export class DataSource implements vscode.Disposable {
* @param includeTags Include commits only referenced by tags.
* @param includeRemotes Include remote branches.
* @param includeCommitsMentionedByReflogs Include commits mentioned by reflogs.
* @param onlyFollowFirstParent Only follow the first parent of commits.
* @param order The order for commits to be returned.
* @param remotes An array of the known remotes.
* @param hideRemotes An array of hidden remotes.
* @param stashes An array of all stashes in the repository.
* @returns An array of commits.
*/
private getLog(repo: string, branches: string[] | null, num: number, includeTags: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, order: CommitOrdering, remotes: string[], hideRemotes: string[], stashes: ReadonlyArray<GitStash>) {
private getLog(repo: string, branches: string[] | null, num: number, includeTags: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, order: CommitOrdering, remotes: string[], hideRemotes: string[], stashes: ReadonlyArray<GitStash>) {
let args = ['log', '--max-count=' + num, '--format=' + this.gitFormatLog, '--' + order + '-order'];
if (onlyFollowFirstParent) args.push('--first-parent');
if (branches !== null) {
for (let i = 0; i < branches.length; i++) {
args.push(branches[i]);
Expand Down
3 changes: 2 additions & 1 deletion src/extensionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as fs from 'fs';
import * as vscode from 'vscode';
import { Avatar, AvatarCache } from './avatarManager';
import { Event } from './event';
import { CodeReview, ErrorInfo, FileViewType, GitGraphViewGlobalState, GitRepoSet, GitRepoState, IncludeCommitsMentionedByReflogs, ShowTags } from './types';
import { CodeReview, ErrorInfo, FileViewType, GitGraphViewGlobalState, GitRepoSet, GitRepoState, IncludeCommitsMentionedByReflogs, OnlyFollowFirstParent, ShowTags } from './types';
import { getPathFromStr, GitExecutable } from './utils';

const AVATAR_STORAGE_FOLDER = '/avatars';
Expand All @@ -20,6 +20,7 @@ export const DEFAULT_REPO_STATE: GitRepoState = {
cdvHeight: 250,
fileViewType: FileViewType.Default,
includeCommitsMentionedByReflogs: IncludeCommitsMentionedByReflogs.Default,
onlyFollowFirstParent: OnlyFollowFirstParent.Default,
issueLinkingConfig: null,
pullRequestConfig: null,
showRemoteBranches: true,
Expand Down
4 changes: 3 additions & 1 deletion src/gitGraphView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ export class GitGraphView implements vscode.Disposable {
this.sendMessage({
command: 'loadCommits',
refreshId: msg.refreshId,
... await this.dataSource.getCommits(msg.repo, msg.branches, msg.maxCommits, msg.showTags, msg.showRemoteBranches, msg.includeCommitsMentionedByReflogs, msg.remotes, msg.hideRemotes, msg.stashes)
onlyFollowFirstParent: msg.onlyFollowFirstParent,
... await this.dataSource.getCommits(msg.repo, msg.branches, msg.maxCommits, msg.showTags, msg.showRemoteBranches, msg.includeCommitsMentionedByReflogs, msg.onlyFollowFirstParent, msg.remotes, msg.hideRemotes, msg.stashes)
});
break;
case 'loadRepoInfo':
Expand Down Expand Up @@ -583,6 +584,7 @@ export class GitGraphView implements vscode.Disposable {
loadMoreCommitsAutomatically: config.loadMoreCommitsAutomatically,
muteCommitsNotAncestorsOfHead: config.muteCommitsThatAreNotAncestorsOfHead,
muteMergeCommits: config.muteMergeCommits,
onlyFollowFirstParent: config.onlyFollowFirstParent,
openRepoToHead: config.openRepoToHead,
showCurrentBranchByDefault: config.showCurrentBranchByDefault,
showTags: config.showTags,
Expand Down
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export interface GitRepoState {
cdvHeight: number;
fileViewType: FileViewType;
includeCommitsMentionedByReflogs: IncludeCommitsMentionedByReflogs;
onlyFollowFirstParent: OnlyFollowFirstParent;
issueLinkingConfig: IssueLinkingConfig | null;
pullRequestConfig: PullRequestConfig | null;
showRemoteBranches: boolean;
Expand Down Expand Up @@ -226,6 +227,7 @@ export interface GitGraphViewConfig {
readonly loadMoreCommitsAutomatically: boolean;
readonly muteCommitsNotAncestorsOfHead: boolean;
readonly muteMergeCommits: boolean;
readonly onlyFollowFirstParent: boolean;
readonly openRepoToHead: boolean;
readonly showCurrentBranchByDefault: boolean;
readonly showTags: boolean;
Expand Down Expand Up @@ -407,6 +409,12 @@ export const enum IncludeCommitsMentionedByReflogs {
Disabled
}

export const enum OnlyFollowFirstParent {
Default,
Enabled,
Disabled
}

export const enum RefLabelAlignment {
Normal,
BranchesOnLeftAndTagsOnRight,
Expand Down Expand Up @@ -766,6 +774,7 @@ export interface RequestLoadCommits extends RepoRequest {
readonly showTags: boolean;
readonly showRemoteBranches: boolean;
readonly includeCommitsMentionedByReflogs: boolean;
readonly onlyFollowFirstParent: boolean;
readonly remotes: string[];
readonly hideRemotes: string[];
readonly stashes: ReadonlyArray<GitStash>;
Expand All @@ -776,6 +785,7 @@ export interface ResponseLoadCommits extends ResponseWithErrorInfo {
readonly commits: GitCommit[];
readonly head: string | null;
readonly moreCommitsAvailable: boolean;
readonly onlyFollowFirstParent: boolean;
}

export interface RequestLoadRepos extends BaseMessage {
Expand Down
1 change: 1 addition & 0 deletions web/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ declare global {
readonly currentBranches: string[] | null;
readonly moreCommitsAvailable: boolean;
readonly maxCommits: number;
readonly onlyFollowFirstParent: boolean;
readonly expandedCommit: ExpandedCommit | null;
readonly scrollTop: number;
readonly findWidget: FindWidgetState;
Expand Down
11 changes: 7 additions & 4 deletions web/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ class Graph {
private commits: ReadonlyArray<GG.GitCommit> = [];
private commitHead: string | null = null;
private commitLookup: { [hash: string]: number } = {};
private onlyFollowFirstParent: boolean = false;
private expandedCommitIndex: number = -1;

private readonly viewElem: HTMLElement;
Expand Down Expand Up @@ -388,10 +389,11 @@ class Graph {

/* Graph Operations */

public loadCommits(commits: ReadonlyArray<GG.GitCommit>, commitHead: string | null, commitLookup: { [hash: string]: number }) {
public loadCommits(commits: ReadonlyArray<GG.GitCommit>, commitHead: string | null, commitLookup: { [hash: string]: number }, onlyFollowFirstParent: boolean) {
this.commits = commits;
this.commitHead = commitHead;
this.commitLookup = commitLookup;
this.onlyFollowFirstParent = onlyFollowFirstParent;
this.vertices = [];
this.branches = [];
this.availableColours = [];
Expand All @@ -409,8 +411,8 @@ class Graph {
// Parent is the <commitLookup[parentHash]>th vertex
this.vertices[i].addParent(this.vertices[commitLookup[parentHash]]);
this.vertices[commitLookup[parentHash]].addChild(this.vertices[i]);
} else {
// Parent is not one of the vertices of the graph
} else if (!this.onlyFollowFirstParent || j === 0) {
// Parent is not one of the vertices of the graph, and the parent isn't being hidden by the onlyFollowFirstParent condition.
this.vertices[i].addParent(nullVertex);
}
}
Expand Down Expand Up @@ -536,7 +538,8 @@ class Graph {
// Mute any merge commits if the Extension Setting is enabled
if (this.config.muteMergeCommits) {
for (let i = 0; i < this.commits.length; i++) {
if (this.commits[i].parents.length > 1 && this.commits[i].stash === null) {
if (this.vertices[i].isMerge() && this.commits[i].stash === null) {
// The commit is a merge, and is not a stash
muted[i] = true;
}
}
Expand Down
66 changes: 48 additions & 18 deletions web/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class GitGraphView {
private commits: GG.GitCommit[] = [];
private commitHead: string | null = null;
private commitLookup: { [hash: string]: number } = {};
private onlyFollowFirstParent: boolean = false;
private avatars: AvatarImageCollection = {};
private currentBranches: string[] | null = null;

Expand Down Expand Up @@ -116,11 +117,11 @@ class GitGraphView {
this.expandedCommit = prevState.expandedCommit;
this.avatars = prevState.avatars;
this.loadRepoInfo(prevState.gitBranches, prevState.gitBranchHead, prevState.gitRemotes, prevState.gitStashes, true);
this.loadCommits(prevState.commits, prevState.commitHead, prevState.moreCommitsAvailable);
this.loadCommits(prevState.commits, prevState.commitHead, prevState.moreCommitsAvailable, prevState.onlyFollowFirstParent);
this.findWidget.restoreState(prevState.findWidget);
if (this.currentRepo === prevState.settingsWidget.repo) {
const currentRepoState = this.gitRepos[this.currentRepo];
this.settingsWidget.restoreState(prevState.settingsWidget, currentRepoState.hideRemotes, currentRepoState.issueLinkingConfig, currentRepoState.pullRequestConfig, currentRepoState.showTags, currentRepoState.includeCommitsMentionedByReflogs);
this.settingsWidget.restoreState(prevState.settingsWidget, currentRepoState.hideRemotes, currentRepoState.issueLinkingConfig, currentRepoState.pullRequestConfig, currentRepoState.showTags, currentRepoState.includeCommitsMentionedByReflogs, currentRepoState.onlyFollowFirstParent);
}
this.showRemoteBranchesElem.checked = this.gitRepos[prevState.currentRepo].showRemoteBranches;
}
Expand Down Expand Up @@ -149,7 +150,7 @@ class GitGraphView {
settingsBtn.innerHTML = SVG_ICONS.gear;
settingsBtn.addEventListener('click', () => {
const currentRepoState = this.gitRepos[this.currentRepo];
this.settingsWidget.show(this.currentRepo, currentRepoState.hideRemotes, currentRepoState.issueLinkingConfig, currentRepoState.pullRequestConfig, currentRepoState.showTags, currentRepoState.includeCommitsMentionedByReflogs, true);
this.settingsWidget.show(this.currentRepo, currentRepoState.hideRemotes, currentRepoState.issueLinkingConfig, currentRepoState.pullRequestConfig, currentRepoState.showTags, currentRepoState.includeCommitsMentionedByReflogs, currentRepoState.onlyFollowFirstParent, true);
});
}

Expand Down Expand Up @@ -281,8 +282,8 @@ class GitGraphView {
}
}

private loadCommits(commits: GG.GitCommit[], commitHead: string | null, moreAvailable: boolean) {
if (!this.currentRepoLoading && !this.currentRepoRefreshState.hard && this.moreCommitsAvailable === moreAvailable && this.commitHead === commitHead && commits.length > 0 && arraysEqual(this.commits, commits, (a, b) =>
private loadCommits(commits: GG.GitCommit[], commitHead: string | null, moreAvailable: boolean, onlyFollowFirstParent: boolean) {
if (!this.currentRepoLoading && !this.currentRepoRefreshState.hard && this.moreCommitsAvailable === moreAvailable && this.onlyFollowFirstParent === onlyFollowFirstParent && this.commitHead === commitHead && commits.length > 0 && arraysEqual(this.commits, commits, (a, b) =>
a.hash === b.hash &&
arraysStrictlyEqual(a.heads, b.heads) &&
arraysEqual(a.tags, b.tags, (a, b) => a.name === b.name && a.annotated === b.annotated) &&
Expand Down Expand Up @@ -316,6 +317,7 @@ class GitGraphView {
const currentRepoLoading = this.currentRepoLoading;
this.currentRepoLoading = false;
this.moreCommitsAvailable = moreAvailable;
this.onlyFollowFirstParent = onlyFollowFirstParent;
this.commits = commits;
this.commitHead = commitHead;
this.commitLookup = {};
Expand Down Expand Up @@ -346,7 +348,7 @@ class GitGraphView {

this.saveState();

this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup);
this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup, this.onlyFollowFirstParent);
this.render();

if (currentRepoLoading && this.config.openRepoToHead && this.commitHead !== null) {
Expand Down Expand Up @@ -416,7 +418,7 @@ class GitGraphView {
this.renderedGitBranchHead = null;
this.closeCommitDetails(false);
this.saveState();
this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup);
this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup, this.onlyFollowFirstParent);
this.tableElem.innerHTML = '';
this.footerElem.innerHTML = '';
this.renderGraph();
Expand All @@ -437,7 +439,7 @@ class GitGraphView {
if (msg.error === null) {
const refreshState = this.currentRepoRefreshState;
if (refreshState.inProgress && refreshState.loadCommitsRefreshId === msg.refreshId) {
this.loadCommits(msg.commits, msg.head, msg.moreCommitsAvailable);
this.loadCommits(msg.commits, msg.head, msg.moreCommitsAvailable, msg.onlyFollowFirstParent);
}
} else {
const error = this.gitBranches.length === 0 && msg.error.indexOf('bad revision \'HEAD\'') > -1
Expand Down Expand Up @@ -496,31 +498,30 @@ class GitGraphView {
/* Requests */

private requestLoadRepoInfo() {
const repoState = this.gitRepos[this.currentRepo];
sendMessage({
command: 'loadRepoInfo',
repo: this.currentRepo,
refreshId: ++this.currentRepoRefreshState.loadRepoInfoRefreshId,
showRemoteBranches: this.gitRepos[this.currentRepo].showRemoteBranches,
hideRemotes: this.gitRepos[this.currentRepo].hideRemotes
showRemoteBranches: repoState.showRemoteBranches,
hideRemotes: repoState.hideRemotes
});
}

private requestLoadCommits() {
const repoState = this.gitRepos[this.currentRepo];
sendMessage({
command: 'loadCommits',
repo: this.currentRepo,
refreshId: ++this.currentRepoRefreshState.loadCommitsRefreshId,
branches: this.currentBranches === null || (this.currentBranches.length === 1 && this.currentBranches[0] === SHOW_ALL_BRANCHES) ? null : this.currentBranches,
maxCommits: this.maxCommits,
showTags: this.gitRepos[this.currentRepo].showTags === GG.ShowTags.Default
? this.config.showTags
: this.gitRepos[this.currentRepo].showTags === GG.ShowTags.Show,
showRemoteBranches: this.gitRepos[this.currentRepo].showRemoteBranches,
includeCommitsMentionedByReflogs: this.gitRepos[this.currentRepo].includeCommitsMentionedByReflogs === GG.IncludeCommitsMentionedByReflogs.Default
? this.config.includeCommitsMentionedByReflogs
: this.gitRepos[this.currentRepo].includeCommitsMentionedByReflogs === GG.IncludeCommitsMentionedByReflogs.Enabled,
showTags: getShowTags(repoState.showTags),
showRemoteBranches: repoState.showRemoteBranches,
includeCommitsMentionedByReflogs: getIncludeCommitsMentionedByReflogs(repoState.includeCommitsMentionedByReflogs),
onlyFollowFirstParent: getOnlyFollowFirstParent(repoState.onlyFollowFirstParent),
remotes: this.gitRemotes,
hideRemotes: this.gitRepos[this.currentRepo].hideRemotes,
hideRemotes: repoState.hideRemotes,
stashes: this.gitStashes
});
}
Expand Down Expand Up @@ -614,6 +615,7 @@ class GitGraphView {
currentBranches: this.currentBranches,
moreCommitsAvailable: this.moreCommitsAvailable,
maxCommits: this.maxCommits,
onlyFollowFirstParent: this.onlyFollowFirstParent,
expandedCommit: expandedCommit,
scrollTop: this.scrollTop,
findWidget: this.findWidget.getState(),
Expand Down Expand Up @@ -677,6 +679,13 @@ class GitGraphView {
}
}

public saveOnlyFollowFirstParentConfig(repo: string, onlyFollowFirstParent: GG.OnlyFollowFirstParent) {
if (repo === this.currentRepo) {
this.gitRepos[this.currentRepo].onlyFollowFirstParent = onlyFollowFirstParent;
this.saveRepoState();
}
}

public saveShowTagsConfig(repo: string, showTags: GG.ShowTags) {
if (repo === this.currentRepo) {
this.gitRepos[this.currentRepo].showTags = showTags;
Expand Down Expand Up @@ -3024,6 +3033,27 @@ function getChildByPathSegment(folder: FileTreeFolder, pathSeg: string) {
}


/* Repository State Helpers */

function getShowTags(repoValue: GG.ShowTags) {
return repoValue === GG.ShowTags.Default
? initialState.config.showTags
: repoValue === GG.ShowTags.Show;
}

function getIncludeCommitsMentionedByReflogs(repoValue: GG.IncludeCommitsMentionedByReflogs) {
return repoValue === GG.IncludeCommitsMentionedByReflogs.Default
? initialState.config.includeCommitsMentionedByReflogs
: repoValue === GG.IncludeCommitsMentionedByReflogs.Enabled;
}

function getOnlyFollowFirstParent(repoValue: GG.OnlyFollowFirstParent) {
return repoValue === GG.OnlyFollowFirstParent.Default
? initialState.config.onlyFollowFirstParent
: repoValue === GG.OnlyFollowFirstParent.Enabled;
}


/* Miscellaneous Helper Methods */

function haveFilesChanged(oldFiles: ReadonlyArray<GG.GitFileChange> | null, newFiles: ReadonlyArray<GG.GitFileChange> | null) {
Expand Down
Loading

0 comments on commit 414545a

Please sign in to comment.