From 3856cfd110977004abd2d2bee6295811c0a529bc Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 26 Mar 2017 13:50:04 -0400 Subject: [PATCH] Fixes issues with merge commits --- CHANGELOG.md | 1 + src/git/git.ts | 17 +++++++++++++---- src/git/models/logCommit.ts | 5 +++++ src/git/parsers/logParser.ts | 9 +++++---- src/gitService.ts | 18 +++++++++--------- src/quickPicks/commitFileDetails.ts | 6 +++++- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce3a913..87f691f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Fixes various other quick pick command issues when a file was renamed - Fixes various issues when caching is disabled - Fixes issues with parsing commits history +- Fixes various issues with merge commits ### 2.12.2 - Fixes [#50](https://github.com/eamodio/vscode-gitlens/issues/50) - excludes container-level CodeLens from `html` and `vue` language files diff --git a/src/git/git.ts b/src/git/git.ts index 5a02760..be178c9 100644 --- a/src/git/git.ts +++ b/src/git/git.ts @@ -14,8 +14,8 @@ export * from './remotes/provider'; let git: IGit; -//`--format=%H -%nauthor %an%nauthor-date %ai%ncommitter %cn%ncommitter-date %ci%nparent %P%nsummary %B%nfilename ?` -const defaultLogParams = [`log`, `--name-status`, `--full-history`, `-M`, `--date=iso8601-strict`, `--format=%H -%nauthor %an%nauthor-date %ai%nsummary %B%nfilename ?`]; +// `--format=%H -%nauthor %an%nauthor-date %ai%ncommitter %cn%ncommitter-date %ci%nparents %P%nsummary %B%nfilename ?` +const defaultLogParams = [`log`, `--name-status`, `--full-history`, `-M`, `--date=iso8601-strict`, `--format=%H -%nauthor %an%nauthor-date %ai%nparents %P%nsummary %B%nfilename ?`]; async function gitCommand(cwd: string, ...args: any[]) { try { @@ -166,7 +166,7 @@ export class Git { } static log(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false) { - const params = [...defaultLogParams]; + const params = [...defaultLogParams, `-m`]; if (maxCount && !reverse) { params.push(`-n${maxCount}`); } @@ -186,10 +186,19 @@ export class Git { static log_file(repoPath: string, fileName: string, sha?: string, maxCount?: number, reverse: boolean = false, startLine?: number, endLine?: number) { const [file, root] = Git.splitPath(fileName, repoPath); - const params = [...defaultLogParams, `--no-merges`, `--follow`]; + const params = [...defaultLogParams, `--follow`]; if (maxCount && !reverse) { params.push(`-n${maxCount}`); } + + // If we are looking for a specific sha don't exclude merge commits + if (!sha || maxCount > 2) { + params.push(`--no-merges`); + } + else { + params.push(`-m`); + } + if (sha) { if (reverse) { params.push(`--reverse`); diff --git a/src/git/models/logCommit.ts b/src/git/models/logCommit.ts index d5a88ff..f2074b5 100644 --- a/src/git/models/logCommit.ts +++ b/src/git/models/logCommit.ts @@ -12,6 +12,7 @@ export class GitLogCommit extends GitCommit { fileStatuses: { status: GitStatusFileStatus, fileName: string, originalFileName?: string }[]; nextSha?: string; nextFileName?: string; + parentShas: string[]; status: GitStatusFileStatus; constructor( @@ -43,6 +44,10 @@ export class GitLogCommit extends GitCommit { } } + get isMerge() { + return this.parentShas && this.parentShas.length > 1; + } + get nextShortSha() { return this.nextSha && this.nextSha.substring(0, 8); } diff --git a/src/git/parsers/logParser.ts b/src/git/parsers/logParser.ts index 76386f9..7158055 100644 --- a/src/git/parsers/logParser.ts +++ b/src/git/parsers/logParser.ts @@ -14,7 +14,7 @@ interface ILogEntry { // committer?: string; // committerDate?: string; - // parentSha?: string; + parentShas?: string[]; fileName?: string; originalFileName?: string; @@ -75,9 +75,9 @@ export class GitLogParser { // entry.committerDate = lineParts.slice(1).join(' ').trim(); // break; - // case 'parent': - // entry.parentSha = lineParts.slice(1).join(' ').trim(); - // break; + case 'parents': + entry.parentShas = lineParts.slice(1); + break; case 'summary': entry.summary = lineParts.slice(1).join(' ').trim(); @@ -227,6 +227,7 @@ export class GitLogParser { } commit = new GitLogCommit(type, repoPath, entry.sha, relativeFileName, entry.author, moment(entry.authorDate).toDate(), entry.summary, entry.status, entry.fileStatuses, undefined, entry.originalFileName); + commit.parentShas = entry.parentShas; if (relativeFileName !== entry.fileName) { commit.originalFileName = entry.fileName; diff --git a/src/gitService.ts b/src/gitService.ts index 8492328..ef13201 100644 --- a/src/gitService.ts +++ b/src/gitService.ts @@ -229,13 +229,13 @@ export class GitService extends Disposable { } async findNextCommit(repoPath: string, fileName: string, sha?: string): Promise { - let log = await this.getLogForFile(repoPath, fileName, sha, 1, undefined, { follow: true, reverse: true }); + let log = await this.getLogForFile(repoPath, fileName, sha, 1, undefined, true); let commit = log && Iterables.first(log.commits.values()); if (commit) return commit; fileName = await this.findNextFileName(repoPath, fileName, sha); if (fileName) { - log = await this.getLogForFile(repoPath, fileName, sha, 1, undefined, { follow: true, reverse: true }); + log = await this.getLogForFile(repoPath, fileName, sha, 1, undefined, true); commit = log && Iterables.first(log.commits.values()); } @@ -551,11 +551,11 @@ export class GitService extends Disposable { } } - getLogForFile(repoPath: string, fileName: string, sha?: string, maxCount?: number, range?: Range, options: { follow?: boolean, reverse?: boolean } = {}): Promise { - Logger.log(`getLogForFile('${repoPath}', '${fileName}', ${sha}, ${maxCount}, ${range && `[${range.start.line}, ${range.end.line}]`}, ${options})`); + getLogForFile(repoPath: string, fileName: string, sha?: string, maxCount?: number, range?: Range, reverse: boolean = false): Promise { + Logger.log(`getLogForFile('${repoPath}', '${fileName}', ${sha}, ${maxCount}, ${range && `[${range.start.line}, ${range.end.line}]`}, ${reverse})`); let entry: GitCacheEntry | undefined; - if (this.UseGitCaching && !sha && !range && !maxCount && !options.reverse) { + if (this.UseGitCaching && !sha && !range && !maxCount && !reverse) { const cacheKey = this.getCacheEntryKey(fileName); entry = this._gitCache.get(cacheKey); @@ -565,7 +565,7 @@ export class GitService extends Disposable { } } - const promise = this._getLogForFile(repoPath, fileName, sha, range, maxCount, options, entry); + const promise = this._getLogForFile(repoPath, fileName, sha, range, maxCount, reverse, entry); if (entry) { Logger.log(`Add log cache for '${entry.key}'`); @@ -581,7 +581,7 @@ export class GitService extends Disposable { return promise; } - private async _getLogForFile(repoPath: string, fileName: string, sha: string, range: Range, maxCount: number, options: { follow?: boolean, reverse?: boolean } = {}, entry: GitCacheEntry | undefined): Promise { + private async _getLogForFile(repoPath: string, fileName: string, sha: string, range: Range, maxCount: number, reverse: boolean, entry: GitCacheEntry | undefined): Promise { const [file, root] = Git.splitPath(fileName, repoPath, false); const ignore = await this._gitignore; @@ -591,8 +591,8 @@ export class GitService extends Disposable { } try { - const data = await Git.log_file(root, file, sha, maxCount, options.reverse, range && range.start.line + 1, range && range.end.line + 1); - return GitLogParser.parse(data, 'file', root || file, sha, maxCount, !!root, options.reverse, range); + const data = await Git.log_file(root, file, sha, maxCount, reverse, range && range.start.line + 1, range && range.end.line + 1); + return GitLogParser.parse(data, 'file', root || file, sha, maxCount, !!root, reverse, range); } catch (ex) { // Trap and cache expected log errors diff --git a/src/quickPicks/commitFileDetails.ts b/src/quickPicks/commitFileDetails.ts index 6265f98..3cc64d5 100644 --- a/src/quickPicks/commitFileDetails.ts +++ b/src/quickPicks/commitFileDetails.ts @@ -1,5 +1,5 @@ 'use strict'; -import { Arrays } from '../system'; +import { Arrays, Iterables } from '../system'; import { QuickPickItem, QuickPickOptions, Uri, window } from 'vscode'; import { Commands, Keyboard, KeyNoopCommand } from '../commands'; import { GitCommit, GitLogCommit, GitService, GitUri, IGitLog } from '../gitService'; @@ -118,6 +118,10 @@ export class CommitFileDetailsQuickPick { if (!c || !c.previousSha) { log = await git.getLogForFile(commit.repoPath, uri.fsPath, commit.sha, git.config.advanced.maxQuickHistory); c = log && log.commits.get(commit.sha); + // Since we exclude merge commits in file log, just grab the first returned commit + if (!c && commit.isMerge) { + c = Iterables.first(log.commits.values()); + } if (c) { // Copy over next info, since it is trustworthy at this point