From 1714d2acc5d67120dbc14c0ce94c8d0ab35c487c Mon Sep 17 00:00:00 2001 From: TheBrenny Date: Sun, 3 Apr 2022 14:05:41 +0930 Subject: [PATCH 1/3] windows uses rn, and *nix-like uses n, so drop just r --- src/dataSource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dataSource.ts b/src/dataSource.ts index 10a3429f..93bf3ba3 100644 --- a/src/dataSource.ts +++ b/src/dataSource.ts @@ -12,7 +12,7 @@ import { Disposable } from './utils/disposable'; import { Event } from './utils/event'; const DRIVE_LETTER_PATH_REGEX = /^[a-z]:\//; -const EOL_REGEX = /\r\n|\r|\n/g; +const EOL_REGEX = /\r\n|\n/g; const INVALID_BRANCH_REGEXP = /^\(.* .*\)$/; const REMOTE_HEAD_BRANCH_REGEXP = /^remotes\/.*\/HEAD$/; const GIT_LOG_SEPARATOR = 'XX7Nal-YARtTpjCikii9nJxER19D6diSyk-AWkPb'; From ce09159acb8c4ef6a1774599f74f27725e4c5ecc Mon Sep 17 00:00:00 2001 From: i11010520 Date: Mon, 18 Apr 2022 16:26:10 +0800 Subject: [PATCH 2/3] To add the support of viewing commits in reverse order --- .gitignore | 2 ++ package.json | 9 ++++-- src/config.ts | 7 +++++ src/dataSource.ts | 26 +++++++++++++----- src/extensionState.ts | 1 + src/gitGraphView.ts | 5 +++- src/types.ts | 5 ++++ web/graph.ts | 64 +++++++++++++++++++++++++++++-------------- web/main.ts | 35 +++++++++++++++++++---- 9 files changed, 117 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 975111a6..158ec8db 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ media node_modules out *.vsix +yarn.lock +package-lock.json diff --git a/package.json b/package.json index 3d024431..cb0a74f2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "git-graph", "displayName": "Git Graph", - "version": "1.30.0", + "version": "1.30.1", "publisher": "mhutchie", "author": { "name": "Michael Hutchison", @@ -1072,6 +1072,11 @@ "default": true, "description": "Show Commits that are only referenced by tags in Git Graph." }, + "git-graph.repository.showReverseCommits": { + "type": "boolean", + "default": false, + "description": "Show Commits in reverse order by default. This can be overridden per repository from the Git Graph View's Control Bar." + }, "git-graph.repository.showRemoteBranches": { "type": "boolean", "default": true, @@ -1515,7 +1520,7 @@ "vscode:prepublish": "npm run compile", "vscode:uninstall": "node ./out/life-cycle/uninstall.js", "clean": "node ./.vscode/clean.js", - "compile": "npm run lint && npm run clean && npm run compile-src && npm run compile-web", + "compile": "npm run lint && npm run clean && npm run compile-src && npm run compile-web-debug", "compile-src": "tsc -p ./src && node ./.vscode/package-src.js", "compile-web": "tsc -p ./web && node ./.vscode/package-web.js", "compile-web-debug": "tsc -p ./web && node ./.vscode/package-web.js debug", diff --git a/src/config.ts b/src/config.ts index 8d777ca8..d557677b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -457,6 +457,13 @@ class Config { return !!this.getRenamedExtensionSetting('repository.showCommitsOnlyReferencedByTags', 'showCommitsOnlyReferencedByTags', true); } + /** + * Get the value of the `git-graph.repository.showReverseCommits` Extension Setting. + */ + get showReverseCommits() { + return !!this.config.get('repository.showReverseCommits', false); + } + /** * Get the value of the `git-graph.repository.showRemoteBranches` Extension Setting. */ diff --git a/src/dataSource.ts b/src/dataSource.ts index 10a3429f..4dcbaf1d 100644 --- a/src/dataSource.ts +++ b/src/dataSource.ts @@ -12,7 +12,7 @@ import { Disposable } from './utils/disposable'; import { Event } from './utils/event'; const DRIVE_LETTER_PATH_REGEX = /^[a-z]:\//; -const EOL_REGEX = /\r\n|\r|\n/g; +const EOL_REGEX = /\r\n|\n/g; const INVALID_BRANCH_REGEXP = /^\(.* .*\)$/; const REMOTE_HEAD_BRANCH_REGEXP = /^remotes\/.*\/HEAD$/; const GIT_LOG_SEPARATOR = 'XX7Nal-YARtTpjCikii9nJxER19D6diSyk-AWkPb'; @@ -161,10 +161,10 @@ export class DataSource extends Disposable { * @param stashes An array of all stashes in the repository. * @returns The commits in the repository. */ - public getCommits(repo: string, branches: ReadonlyArray | null, maxCommits: number, showTags: boolean, showRemoteBranches: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, commitOrdering: CommitOrdering, remotes: ReadonlyArray, hideRemotes: ReadonlyArray, stashes: ReadonlyArray): Promise { + public getCommits(repo: string, branches: ReadonlyArray | null, maxCommits: number, showTags: boolean, showReverseCommits: boolean, showRemoteBranches: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, commitOrdering: CommitOrdering, remotes: ReadonlyArray, hideRemotes: ReadonlyArray, stashes: ReadonlyArray): Promise { const config = getConfig(); return Promise.all([ - this.getLog(repo, branches, maxCommits + 1, showTags && config.showCommitsOnlyReferencedByTags, showRemoteBranches, includeCommitsMentionedByReflogs, onlyFollowFirstParent, commitOrdering, remotes, hideRemotes, stashes), + this.getLog(repo, branches, maxCommits + 1, showTags && config.showCommitsOnlyReferencedByTags, showReverseCommits, showRemoteBranches, includeCommitsMentionedByReflogs, onlyFollowFirstParent, commitOrdering, remotes, hideRemotes, stashes), this.getRefs(repo, showRemoteBranches, config.showRemoteHeads, hideRemotes).then((refData: GitRefData) => refData, (errorMessage: string) => errorMessage) ]).then(async (results) => { let commits: GitCommitRecord[] = results[0], refData: GitRefData | string = results[1], i; @@ -188,7 +188,12 @@ export class DataSource extends Disposable { if (refData.head === commits[i].hash) { const numUncommittedChanges = await this.getUncommittedChanges(repo); if (numUncommittedChanges > 0) { - commits.unshift({ hash: UNCOMMITTED, parents: [refData.head], author: '*', email: '', date: Math.round((new Date()).getTime() / 1000), message: 'Uncommitted Changes (' + numUncommittedChanges + ')' }); + const cn = { hash: UNCOMMITTED, parents: [refData.head], author: '*', email: '', date: Math.round((new Date()).getTime() / 1000), message: 'Uncommitted Changes (' + numUncommittedChanges + ')' }; + if (showReverseCommits) { + commits.push(cn); + } else { + commits.unshift(cn); + } } break; } @@ -204,6 +209,7 @@ export class DataSource extends Disposable { } /* Insert Stashes */ + // OK for reverse order? let toAdd: { index: number, data: GitStash }[] = []; for (i = 0; i < stashes.length; i++) { if (typeof commitLookup[stashes[i].hash] === 'number') { @@ -264,7 +270,7 @@ export class DataSource extends Disposable { commits: commitNodes, head: refData.head, tags: unique(refData.tags.map((tag) => tag.name)), - moreCommitsAvailable: moreCommitsAvailable, + moreCommitsAvailable: showReverseCommits ? false : moreCommitsAvailable, error: null }; }).catch((errorMessage) => { @@ -1496,8 +1502,14 @@ export class DataSource extends Disposable { * @param stashes An array of all stashes in the repository. * @returns An array of commits. */ - private getLog(repo: string, branches: ReadonlyArray | null, num: number, includeTags: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, order: CommitOrdering, remotes: ReadonlyArray, hideRemotes: ReadonlyArray, stashes: ReadonlyArray) { - const args = ['-c', 'log.showSignature=false', 'log', '--max-count=' + num, '--format=' + this.gitFormatLog, '--' + order + '-order']; + private getLog(repo: string, branches: ReadonlyArray | null, num: number, includeTags: boolean, showReverseCommits: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, order: CommitOrdering, remotes: ReadonlyArray, hideRemotes: ReadonlyArray, stashes: ReadonlyArray) { + let args = []; + if (showReverseCommits) { + args = ['-c', 'log.showSignature=false', 'log', '--format=' + this.gitFormatLog, '--date-order', '--reverse']; + } else { + args = ['-c', 'log.showSignature=false', 'log', '--max-count=' + num, '--format=' + this.gitFormatLog, '--' + order + '-order']; + } + // const args = ['-c', 'log.showSignature=false', 'log', '--max-count=' + num, '--format=' + this.gitFormatLog, '--' + order + '-order']; if (onlyFollowFirstParent) { args.push('--first-parent'); } diff --git a/src/extensionState.ts b/src/extensionState.ts index 721857a4..fb767568 100644 --- a/src/extensionState.ts +++ b/src/extensionState.ts @@ -32,6 +32,7 @@ export const DEFAULT_REPO_STATE: GitRepoState = { onRepoLoadShowCheckedOutBranch: BooleanOverride.Default, onRepoLoadShowSpecificBranches: null, pullRequestConfig: null, + showReverseCommits: false, showRemoteBranches: true, showRemoteBranchesV2: BooleanOverride.Default, showStashes: BooleanOverride.Default, diff --git a/src/gitGraphView.ts b/src/gitGraphView.ts index 1acba6ff..c248b741 100644 --- a/src/gitGraphView.ts +++ b/src/gitGraphView.ts @@ -409,7 +409,8 @@ export class GitGraphView extends Disposable { command: 'loadCommits', refreshId: msg.refreshId, onlyFollowFirstParent: msg.onlyFollowFirstParent, - ...await this.dataSource.getCommits(msg.repo, msg.branches, msg.maxCommits, msg.showTags, msg.showRemoteBranches, msg.includeCommitsMentionedByReflogs, msg.onlyFollowFirstParent, msg.commitOrdering, msg.remotes, msg.hideRemotes, msg.stashes) + showReverseCommits: msg.showReverseCommits, + ...await this.dataSource.getCommits(msg.repo, msg.branches, msg.maxCommits, msg.showTags, msg.showReverseCommits, msg.showRemoteBranches, msg.includeCommitsMentionedByReflogs, msg.onlyFollowFirstParent, msg.commitOrdering, msg.remotes, msg.hideRemotes, msg.stashes) }); break; case 'loadConfig': @@ -690,6 +691,7 @@ export class GitGraphView extends Disposable { onRepoLoad: config.onRepoLoad, referenceLabels: config.referenceLabels, repoDropdownOrder: config.repoDropdownOrder, + showReverseCommits: config.showReverseCommits, showRemoteBranches: config.showRemoteBranches, showStashes: config.showStashes, showTags: config.showTags @@ -720,6 +722,7 @@ export class GitGraphView extends Disposable {
Repo: Branches: +
diff --git a/src/types.ts b/src/types.ts index c543fa9f..6a56ef52 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,6 @@ /* Git Interfaces / Types */ + export interface GitCommit { readonly hash: string; readonly parents: ReadonlyArray; @@ -212,6 +213,7 @@ export interface GitRepoState { onRepoLoadShowCheckedOutBranch: BooleanOverride; onRepoLoadShowSpecificBranches: string[] | null; pullRequestConfig: PullRequestConfig | null; + showReverseCommits: boolean; showRemoteBranches: boolean; showRemoteBranchesV2: BooleanOverride; showStashes: BooleanOverride; @@ -257,6 +259,7 @@ export interface GitGraphViewConfig { readonly onRepoLoad: OnRepoLoadConfig; readonly referenceLabels: ReferenceLabelsConfig; readonly repoDropdownOrder: RepoDropdownOrder; + readonly showReverseCommits: boolean; readonly showRemoteBranches: boolean; readonly showStashes: boolean; readonly showTags: boolean; @@ -904,6 +907,7 @@ export interface RequestLoadCommits extends RepoRequest { readonly branches: ReadonlyArray | null; // null => Show All readonly maxCommits: number; readonly showTags: boolean; + readonly showReverseCommits: boolean; readonly showRemoteBranches: boolean; readonly includeCommitsMentionedByReflogs: boolean; readonly onlyFollowFirstParent: boolean; @@ -920,6 +924,7 @@ export interface ResponseLoadCommits extends ResponseWithErrorInfo { readonly tags: string[]; readonly moreCommitsAvailable: boolean; readonly onlyFollowFirstParent: boolean; + readonly showReverseCommits: boolean; } export interface RequestLoadConfig extends RepoRequest { diff --git a/web/graph.ts b/web/graph.ts index 415dfd2e..564baefc 100644 --- a/web/graph.ts +++ b/web/graph.ts @@ -72,11 +72,15 @@ class Branch { /* Rendering */ - public draw(svg: SVGElement, config: GG.GraphConfig, expandAt: number) { - let colour = config.colours[this.colour % config.colours.length], i, x1, y1, x2, y2, lines: PlacedLine[] = [], curPath = '', d = config.grid.y * (config.style === GG.GraphStyle.Angular ? 0.38 : 0.8), line, nextLine; + public draw(svg: SVGElement, config: GG.GraphConfig, expandAt: number, showReverseCommits: boolean) { + let colour = config.colours[this.colour % config.colours.length], i, x1, y1, x2, y2, lines: PlacedLine[] = [], curPath = '', line, nextLine; + let di = config.grid.y * (config.style === GG.GraphStyle.Angular ? 0.38 : 0.8); + let d = showReverseCommits ? -di : di; // Convert branch lines into pixel coordinates, respecting expanded commit extensions - for (i = 0; i < this.lines.length; i++) { + for (showReverseCommits ? i = this.lines.length - 1 : i = 0; + showReverseCommits ? i >= 0 : i < this.lines.length; + showReverseCommits ? i-- : i++) { line = this.lines[i]; x1 = line.p1.x * config.grid.x + config.grid.offsetX; y1 = line.p1.y * config.grid.y + config.grid.offsetY; x2 = line.p2.x * config.grid.x + config.grid.offsetX; y2 = line.p2.y * config.grid.y + config.grid.offsetY; @@ -192,7 +196,6 @@ class Vertex { return this.children; } - /* Parents */ public addParent(vertex: Vertex) { @@ -347,6 +350,7 @@ class Graph { private commitLookup: { [hash: string]: number } = {}; private onlyFollowFirstParent: boolean = false; private expandedCommitIndex: number = -1; + private showReverseCommits: boolean; private readonly viewElem: HTMLElement; private readonly contentElem: HTMLElement; @@ -361,10 +365,11 @@ class Graph { private tooltipTimeout: NodeJS.Timer | null = null; private tooltipVertex: HTMLElement | null = null; - constructor(id: string, viewElem: HTMLElement, config: GG.GraphConfig, muteConfig: GG.MuteCommitsConfig) { + constructor(id: string, viewElem: HTMLElement, config: GG.GraphConfig, muteConfig: GG.MuteCommitsConfig, showReverseCommits: boolean) { this.viewElem = viewElem; this.config = config; this.muteConfig = muteConfig; + this.showReverseCommits = showReverseCommits; const elem = document.getElementById(id)!; this.contentElem = elem.parentElement!; @@ -387,10 +392,13 @@ class Graph { elem.appendChild(this.svg); } + public setShowReverseCommits(flag: boolean) { + this.showReverseCommits = flag; + } /* Graph Operations */ - public loadCommits(commits: ReadonlyArray, commitHead: string | null, commitLookup: { [hash: string]: number }, onlyFollowFirstParent: boolean) { + public loadCommits(commits: ReadonlyArray, commitHead: string | null, commitLookup: { [hash: string]: number }, onlyFollowFirstParent: boolean, showReverseCommits: boolean) { this.commits = commits; this.commitHead = commitHead; this.commitLookup = commitLookup; @@ -419,22 +427,28 @@ class Graph { } } - if (commits[0].hash === UNCOMMITTED) { - this.vertices[0].setNotCommitted(); + let top = showReverseCommits ? commits.length - 1 : 0; + if (commits[top].hash === UNCOMMITTED) { + this.vertices[top].setNotCommitted(); } - if (commits[0].hash === UNCOMMITTED && this.config.uncommittedChanges === GG.GraphUncommittedChangesStyle.OpenCircleAtTheUncommittedChanges) { - this.vertices[0].setCurrent(); + if (commits[top].hash === UNCOMMITTED && this.config.uncommittedChanges === GG.GraphUncommittedChangesStyle.OpenCircleAtTheUncommittedChanges) { + this.vertices[top].setCurrent(); } else if (commitHead !== null && typeof commitLookup[commitHead] === 'number') { this.vertices[commitLookup[commitHead]].setCurrent(); } - i = 0; - while (i < this.vertices.length) { - if (this.vertices[i].getNextParent() !== null || this.vertices[i].isNotOnBranch()) { - this.determinePath(i); + i = showReverseCommits ? this.vertices.length - 1 : 0; + while (showReverseCommits ? i >= 0 : i < this.vertices.length) { + const nv = this.vertices[i].getNextParent(); + if (nv !== null || this.vertices[i].isNotOnBranch()) { + this.determinePath(i, showReverseCommits); } else { - i++; + if (showReverseCommits) { + i--; + } else { + i++; + } } } } @@ -444,8 +458,10 @@ class Graph { let group = document.createElementNS(SVG_NAMESPACE, 'g'), i, contentWidth = this.getContentWidth(); group.setAttribute('mask', 'url(#GraphMask)'); - for (i = 0; i < this.branches.length; i++) { - this.branches[i].draw(group, this.config, this.expandedCommitIndex); + for (this.showReverseCommits ? i = this.branches.length - 1 : i = 0; + this.showReverseCommits ? i >= 0 : i < this.branches.length; + this.showReverseCommits ? i-- : i++) { + this.branches[i].draw(group, this.config, this.expandedCommitIndex, this.showReverseCommits); } const overListener = (e: MouseEvent) => this.vertexOver(e), outListener = (e: MouseEvent) => this.vertexOut(e); @@ -702,7 +718,7 @@ class Graph { /* Graph Layout Methods */ - private determinePath(startAt: number) { + private determinePath(startAt: number, showReverseCommits: boolean) { let i = startAt; let vertex = this.vertices[i], parentVertex = this.vertices[i].getNextParent(), curVertex; let lastPoint = vertex.isNotOnBranch() ? vertex.getNextPoint() : vertex.getPoint(), curPoint; @@ -710,7 +726,9 @@ class Graph { if (parentVertex !== null && parentVertex.id !== NULL_VERTEX_ID && vertex.isMerge() && !vertex.isNotOnBranch() && !parentVertex.isNotOnBranch()) { // Branch is a merge between two vertices already on branches let foundPointToParent = false, parentBranch = parentVertex.getBranch()!; - for (i = startAt + 1; i < this.vertices.length; i++) { + for (showReverseCommits ? i = startAt - 1 : i = startAt + 1; + showReverseCommits ? i >= 0 : i < this.vertices.length; + showReverseCommits ? i-- : i++) { curVertex = this.vertices[i]; curPoint = curVertex.getPointConnectingTo(parentVertex, parentBranch); // Check if there is already a point connecting the ith vertex to the required parent if (curPoint !== null) { @@ -732,7 +750,9 @@ class Graph { let branch = new Branch(this.getAvailableColour(startAt)); vertex.addToBranch(branch, lastPoint.x); vertex.registerUnavailablePoint(lastPoint.x, vertex, branch); - for (i = startAt + 1; i < this.vertices.length; i++) { + for (showReverseCommits ? i = startAt - 1 : i = startAt + 1; + showReverseCommits ? i >= 0 : i < this.vertices.length; + showReverseCommits ? i-- : i++) { curVertex = this.vertices[i]; curPoint = parentVertex === curVertex && !parentVertex.isNotOnBranch() ? curVertex.getPoint() : curVertex.getNextPoint(); branch.addLine(lastPoint, curPoint, vertex.getIsCommitted(), lastPoint.x < curPoint.x); @@ -752,7 +772,9 @@ class Graph { } } } - if (i === this.vertices.length && parentVertex !== null && parentVertex.id === NULL_VERTEX_ID) { + if ((showReverseCommits ? i === -1 : i === this.vertices.length) + && parentVertex !== null + && parentVertex.id === NULL_VERTEX_ID) { // Vertex is the last in the graph, so no more branch can be formed to the parent vertex.registerParentProcessed(); } diff --git a/web/main.ts b/web/main.ts index 29c23c82..2768a9a5 100644 --- a/web/main.ts +++ b/web/main.ts @@ -50,6 +50,7 @@ class GitGraphView { private readonly controlsElem: HTMLElement; private readonly tableElem: HTMLElement; private readonly footerElem: HTMLElement; + private readonly showReverseCommitsElem: HTMLInputElement; private readonly showRemoteBranchesElem: HTMLInputElement; private readonly refreshBtnElem: HTMLElement; private readonly scrollShadowElem: HTMLElement; @@ -77,7 +78,7 @@ class GitGraphView { viewElem.focus(); - this.graph = new Graph('commitGraph', viewElem, this.config.graph, this.config.mute); + this.graph = new Graph('commitGraph', viewElem, this.config.graph, this.config.mute, this.config.showReverseCommits); this.repoDropdown = new Dropdown('repoDropdown', true, false, 'Repos', (values) => { this.loadRepo(values[0]); @@ -91,6 +92,14 @@ class GitGraphView { this.requestLoadRepoInfoAndCommits(true, true); }); + this.showReverseCommitsElem = document.getElementById('showReverseCommitsCheckbox')!; + this.showReverseCommitsElem.addEventListener('change', () => { + let reverse: boolean = this.showReverseCommitsElem.checked; + this.saveRepoStateValue(this.currentRepo, 'showReverseCommits', reverse); + this.graph.setShowReverseCommits(reverse); + this.refresh(true); + }); + this.showRemoteBranchesElem = document.getElementById('showRemoteBranchesCheckbox')!; this.showRemoteBranchesElem.addEventListener('change', () => { this.saveRepoStateValue(this.currentRepo, 'showRemoteBranchesV2', this.showRemoteBranchesElem.checked ? GG.BooleanOverride.Enabled : GG.BooleanOverride.Disabled); @@ -126,9 +135,14 @@ class GitGraphView { this.avatars = prevState.avatars; this.gitConfig = prevState.gitConfig; this.loadRepoInfo(prevState.gitBranches, prevState.gitBranchHead, prevState.gitRemotes, prevState.gitStashes, true); - this.loadCommits(prevState.commits, prevState.commitHead, prevState.gitTags, prevState.moreCommitsAvailable, prevState.onlyFollowFirstParent); this.findWidget.restoreState(prevState.findWidget); this.settingsWidget.restoreState(prevState.settingsWidget); + + let rc = this.gitRepos[prevState.currentRepo].showReverseCommits; + this.loadCommits(prevState.commits, prevState.commitHead, prevState.gitTags, prevState.moreCommitsAvailable, prevState.onlyFollowFirstParent, rc); + this.showReverseCommitsElem.checked = rc; + this.graph.setShowReverseCommits(rc); + this.showRemoteBranchesElem.checked = getShowRemoteBranches(this.gitRepos[prevState.currentRepo].showRemoteBranchesV2); } @@ -207,6 +221,8 @@ class GitGraphView { private loadRepo(repo: string) { this.currentRepo = repo; this.currentRepoLoading = true; + this.showReverseCommitsElem.checked = this.gitRepos[this.currentRepo].showReverseCommits; + this.graph.setShowReverseCommits(this.showReverseCommitsElem.checked); this.showRemoteBranchesElem.checked = getShowRemoteBranches(this.gitRepos[this.currentRepo].showRemoteBranchesV2); this.maxCommits = this.config.initialLoadCommits; this.gitConfig = null; @@ -300,7 +316,7 @@ class GitGraphView { } } - private loadCommits(commits: GG.GitCommit[], commitHead: string | null, tags: ReadonlyArray, moreAvailable: boolean, onlyFollowFirstParent: boolean) { + private loadCommits(commits: GG.GitCommit[], commitHead: string | null, tags: ReadonlyArray, moreAvailable: boolean, onlyFollowFirstParent: boolean, showReverseCommits: boolean) { // This list of tags is just used to provide additional information in the dialogs. Tag information included in commits is used for all other purposes (e.g. rendering, context menus) const tagsChanged = !arraysStrictlyEqual(this.gitTags, tags); this.gitTags = tags; @@ -372,7 +388,7 @@ class GitGraphView { this.saveState(); - this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup, this.onlyFollowFirstParent); + this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup, this.onlyFollowFirstParent, showReverseCommits); this.render(); if (currentRepoLoading && this.config.onRepoLoad.scrollToHead && this.commitHead !== null) { @@ -453,7 +469,7 @@ class GitGraphView { this.renderedGitBranchHead = null; this.closeCommitDetails(false); this.saveState(); - this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup, this.onlyFollowFirstParent); + this.graph.loadCommits(this.commits, this.commitHead, this.commitLookup, this.onlyFollowFirstParent, this.showReverseCommitsElem.checked); this.tableElem.innerHTML = ''; this.footerElem.innerHTML = ''; this.renderGraph(); @@ -475,7 +491,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.tags, msg.moreCommitsAvailable, msg.onlyFollowFirstParent); + this.loadCommits(msg.commits, msg.head, msg.tags, msg.moreCommitsAvailable, msg.onlyFollowFirstParent, msg.showReverseCommits); } } else { const error = this.gitBranches.length === 0 && msg.error.indexOf('bad revision \'HEAD\'') > -1 @@ -611,6 +627,7 @@ class GitGraphView { branches: this.currentBranches === null || (this.currentBranches.length === 1 && this.currentBranches[0] === SHOW_ALL_BRANCHES) ? null : this.currentBranches, maxCommits: this.maxCommits, showTags: getShowTags(repoState.showTags), + showReverseCommits: repoState.showReverseCommits, showRemoteBranches: getShowRemoteBranches(repoState.showRemoteBranchesV2), includeCommitsMentionedByReflogs: getIncludeCommitsMentionedByReflogs(repoState.includeCommitsMentionedByReflogs), onlyFollowFirstParent: getOnlyFollowFirstParent(repoState.onlyFollowFirstParent), @@ -3758,6 +3775,12 @@ function getCommitOrdering(repoValue: GG.RepoCommitOrdering): GG.CommitOrdering } } +// function getShowReverseCommits(repoValue: GG.BooleanOverride) { +// return repoValue === GG.BooleanOverride.Default +// ? initialState.config.showReverseCommits +// : repoValue === GG.BooleanOverride.Enabled; +// } + function getShowRemoteBranches(repoValue: GG.BooleanOverride) { return repoValue === GG.BooleanOverride.Default ? initialState.config.showRemoteBranches From 77c668ddf5cf73d4eaf1ab16a53ff26d6c9a0856 Mon Sep 17 00:00:00 2001 From: i11010520 Date: Thu, 21 Apr 2022 21:00:57 +0800 Subject: [PATCH 3/3] add paging support for reverse order --- src/dataSource.ts | 206 ++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 98 deletions(-) diff --git a/src/dataSource.ts b/src/dataSource.ts index 4dcbaf1d..78ea45ad 100644 --- a/src/dataSource.ts +++ b/src/dataSource.ts @@ -163,118 +163,121 @@ export class DataSource extends Disposable { */ public getCommits(repo: string, branches: ReadonlyArray | null, maxCommits: number, showTags: boolean, showReverseCommits: boolean, showRemoteBranches: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, commitOrdering: CommitOrdering, remotes: ReadonlyArray, hideRemotes: ReadonlyArray, stashes: ReadonlyArray): Promise { const config = getConfig(); - return Promise.all([ - this.getLog(repo, branches, maxCommits + 1, showTags && config.showCommitsOnlyReferencedByTags, showReverseCommits, showRemoteBranches, includeCommitsMentionedByReflogs, onlyFollowFirstParent, commitOrdering, remotes, hideRemotes, stashes), - this.getRefs(repo, showRemoteBranches, config.showRemoteHeads, hideRemotes).then((refData: GitRefData) => refData, (errorMessage: string) => errorMessage) - ]).then(async (results) => { - let commits: GitCommitRecord[] = results[0], refData: GitRefData | string = results[1], i; - let moreCommitsAvailable = commits.length === maxCommits + 1; - if (moreCommitsAvailable) commits.pop(); - - // It doesn't matter if getRefs() was rejected if no commits exist - if (typeof refData === 'string') { - // getRefs() returned an error message (string) - if (commits.length > 0) { - // Commits exist, throw the error - throw refData; - } else { - // No commits exist, so getRefs() will always return an error. Set refData to the default value - refData = { head: null, heads: [], tags: [], remotes: [] }; + + return this.getCommitsCount(repo).then((count) => { + return Promise.all([ + this.getLog(repo, branches, maxCommits + 1, count, showTags && config.showCommitsOnlyReferencedByTags, showReverseCommits, showRemoteBranches, includeCommitsMentionedByReflogs, onlyFollowFirstParent, commitOrdering, remotes, hideRemotes, stashes), + this.getRefs(repo, showRemoteBranches, config.showRemoteHeads, hideRemotes).then((refData: GitRefData) => refData, (errorMessage: string) => errorMessage) + ]).then(async (results) => { + let commits: GitCommitRecord[] = results[0], refData: GitRefData | string = results[1], i; + let moreCommitsAvailable = commits.length === maxCommits + 1; + if (moreCommitsAvailable) commits.pop(); + + // It doesn't matter if getRefs() was rejected if no commits exist + if (typeof refData === 'string') { + // getRefs() returned an error message (string) + if (commits.length > 0) { + // Commits exist, throw the error + throw refData; + } else { + // No commits exist, so getRefs() will always return an error. Set refData to the default value + refData = { head: null, heads: [], tags: [], remotes: [] }; + } } - } - if (refData.head !== null && config.showUncommittedChanges) { - for (i = 0; i < commits.length; i++) { - if (refData.head === commits[i].hash) { - const numUncommittedChanges = await this.getUncommittedChanges(repo); - if (numUncommittedChanges > 0) { - const cn = { hash: UNCOMMITTED, parents: [refData.head], author: '*', email: '', date: Math.round((new Date()).getTime() / 1000), message: 'Uncommitted Changes (' + numUncommittedChanges + ')' }; - if (showReverseCommits) { - commits.push(cn); - } else { - commits.unshift(cn); + if (refData.head !== null && config.showUncommittedChanges) { + for (i = 0; i < commits.length; i++) { + if (refData.head === commits[i].hash) { + const numUncommittedChanges = await this.getUncommittedChanges(repo); + if (numUncommittedChanges > 0) { + const cn = { hash: UNCOMMITTED, parents: [refData.head], author: '*', email: '', date: Math.round((new Date()).getTime() / 1000), message: 'Uncommitted Changes (' + numUncommittedChanges + ')' }; + if (showReverseCommits) { + commits.push(cn); + } else { + commits.unshift(cn); + } } + break; } - break; } } - } - let commitNodes: DeepWriteable[] = []; - let commitLookup: { [hash: string]: number } = {}; + let commitNodes: DeepWriteable[] = []; + let commitLookup: { [hash: string]: number } = {}; - for (i = 0; i < commits.length; i++) { - commitLookup[commits[i].hash] = i; - commitNodes.push({ ...commits[i], heads: [], tags: [], remotes: [], stash: null }); - } - - /* Insert Stashes */ - // OK for reverse order? - let toAdd: { index: number, data: GitStash }[] = []; - for (i = 0; i < stashes.length; i++) { - if (typeof commitLookup[stashes[i].hash] === 'number') { - commitNodes[commitLookup[stashes[i].hash]].stash = { - selector: stashes[i].selector, - baseHash: stashes[i].baseHash, - untrackedFilesHash: stashes[i].untrackedFilesHash - }; - } else if (typeof commitLookup[stashes[i].baseHash] === 'number') { - toAdd.push({ index: commitLookup[stashes[i].baseHash], data: stashes[i] }); + for (i = 0; i < commits.length; i++) { + commitLookup[commits[i].hash] = i; + commitNodes.push({ ...commits[i], heads: [], tags: [], remotes: [], stash: null }); } - } - toAdd.sort((a, b) => a.index !== b.index ? a.index - b.index : b.data.date - a.data.date); - for (i = toAdd.length - 1; i >= 0; i--) { - let stash = toAdd[i].data; - commitNodes.splice(toAdd[i].index, 0, { - hash: stash.hash, - parents: [stash.baseHash], - author: stash.author, - email: stash.email, - date: stash.date, - message: stash.message, - heads: [], tags: [], remotes: [], - stash: { - selector: stash.selector, - baseHash: stash.baseHash, - untrackedFilesHash: stash.untrackedFilesHash + + /* Insert Stashes */ + // OK for reverse order? + let toAdd: { index: number, data: GitStash }[] = []; + for (i = 0; i < stashes.length; i++) { + if (typeof commitLookup[stashes[i].hash] === 'number') { + commitNodes[commitLookup[stashes[i].hash]].stash = { + selector: stashes[i].selector, + baseHash: stashes[i].baseHash, + untrackedFilesHash: stashes[i].untrackedFilesHash + }; + } else if (typeof commitLookup[stashes[i].baseHash] === 'number') { + toAdd.push({ index: commitLookup[stashes[i].baseHash], data: stashes[i] }); } - }); - } - for (i = 0; i < commitNodes.length; i++) { - // Correct commit lookup after stashes have been spliced in - commitLookup[commitNodes[i].hash] = i; - } + } + toAdd.sort((a, b) => a.index !== b.index ? a.index - b.index : b.data.date - a.data.date); + for (i = toAdd.length - 1; i >= 0; i--) { + let stash = toAdd[i].data; + commitNodes.splice(toAdd[i].index, 0, { + hash: stash.hash, + parents: [stash.baseHash], + author: stash.author, + email: stash.email, + date: stash.date, + message: stash.message, + heads: [], tags: [], remotes: [], + stash: { + selector: stash.selector, + baseHash: stash.baseHash, + untrackedFilesHash: stash.untrackedFilesHash + } + }); + } + for (i = 0; i < commitNodes.length; i++) { + // Correct commit lookup after stashes have been spliced in + commitLookup[commitNodes[i].hash] = i; + } - /* Annotate Heads */ - for (i = 0; i < refData.heads.length; i++) { - if (typeof commitLookup[refData.heads[i].hash] === 'number') commitNodes[commitLookup[refData.heads[i].hash]].heads.push(refData.heads[i].name); - } + /* Annotate Heads */ + for (i = 0; i < refData.heads.length; i++) { + if (typeof commitLookup[refData.heads[i].hash] === 'number') commitNodes[commitLookup[refData.heads[i].hash]].heads.push(refData.heads[i].name); + } - /* Annotate Tags */ - if (showTags) { - for (i = 0; i < refData.tags.length; i++) { - if (typeof commitLookup[refData.tags[i].hash] === 'number') commitNodes[commitLookup[refData.tags[i].hash]].tags.push({ name: refData.tags[i].name, annotated: refData.tags[i].annotated }); + /* Annotate Tags */ + if (showTags) { + for (i = 0; i < refData.tags.length; i++) { + if (typeof commitLookup[refData.tags[i].hash] === 'number') commitNodes[commitLookup[refData.tags[i].hash]].tags.push({ name: refData.tags[i].name, annotated: refData.tags[i].annotated }); + } } - } - /* Annotate Remotes */ - for (i = 0; i < refData.remotes.length; i++) { - if (typeof commitLookup[refData.remotes[i].hash] === 'number') { - let name = refData.remotes[i].name; - let remote = remotes.find(remote => name.startsWith(remote + '/')); - commitNodes[commitLookup[refData.remotes[i].hash]].remotes.push({ name: name, remote: remote ? remote : null }); + /* Annotate Remotes */ + for (i = 0; i < refData.remotes.length; i++) { + if (typeof commitLookup[refData.remotes[i].hash] === 'number') { + let name = refData.remotes[i].name; + let remote = remotes.find(remote => name.startsWith(remote + '/')); + commitNodes[commitLookup[refData.remotes[i].hash]].remotes.push({ name: name, remote: remote ? remote : null }); + } } - } - return { - commits: commitNodes, - head: refData.head, - tags: unique(refData.tags.map((tag) => tag.name)), - moreCommitsAvailable: showReverseCommits ? false : moreCommitsAvailable, - error: null - }; - }).catch((errorMessage) => { - return { commits: [], head: null, tags: [], moreCommitsAvailable: false, error: errorMessage }; + return { + commits: commitNodes, + head: refData.head, + tags: unique(refData.tags.map((tag) => tag.name)), + moreCommitsAvailable: moreCommitsAvailable, + error: null + }; + }).catch((errorMessage) => { + return { commits: [], head: null, tags: [], moreCommitsAvailable: false, error: errorMessage }; + }); }); } @@ -458,6 +461,11 @@ export class DataSource extends Disposable { /* Get Data Methods - General */ + public getCommitsCount(repo: string): Promise { + return this.spawnGit(['rev-list', '--all', '--count'], repo, (stdout) => { + return Number.parseInt(stdout); + }).then((count) => count, () => 0); + } /** * Get the subject of a commit. * @param repo The path of the repository. @@ -1502,10 +1510,12 @@ export class DataSource extends Disposable { * @param stashes An array of all stashes in the repository. * @returns An array of commits. */ - private getLog(repo: string, branches: ReadonlyArray | null, num: number, includeTags: boolean, showReverseCommits: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, order: CommitOrdering, remotes: ReadonlyArray, hideRemotes: ReadonlyArray, stashes: ReadonlyArray) { + private getLog(repo: string, branches: ReadonlyArray | null, num: number, allcount: number, includeTags: boolean, showReverseCommits: boolean, includeRemotes: boolean, includeCommitsMentionedByReflogs: boolean, onlyFollowFirstParent: boolean, order: CommitOrdering, remotes: ReadonlyArray, hideRemotes: ReadonlyArray, stashes: ReadonlyArray) { let args = []; if (showReverseCommits) { - args = ['-c', 'log.showSignature=false', 'log', '--format=' + this.gitFormatLog, '--date-order', '--reverse']; + let skipnum = allcount - num; + if (skipnum <= 0) skipnum = 0; + args = ['-c', 'log.showSignature=false', 'log', '--skip=' + skipnum, '--format=' + this.gitFormatLog, '--date-order', '--reverse']; } else { args = ['-c', 'log.showSignature=false', 'log', '--max-count=' + num, '--format=' + this.gitFormatLog, '--' + order + '-order']; }