Browse Source

Overhauls previous line diffing - closes #719

Changes & Details hovers now know about staged vs unstaged changes
Significantly increased accuracy with the following:
  - Open Line Changes with Previous Revision
  - Open Changes with Previous Revision
  - Changes & Details hovers
main
Eric Amodio 5 years ago
parent
commit
643e2262df
11 changed files with 356 additions and 200 deletions
  1. +114
    -54
      src/annotations/annotations.ts
  2. +3
    -0
      src/annotations/lineAnnotationController.ts
  3. +1
    -1
      src/annotations/recentChangesAnnotationProvider.ts
  4. +3
    -57
      src/commands/diffLineWithPrevious.ts
  5. +1
    -1
      src/commands/externalDiff.ts
  6. +51
    -14
      src/git/formatters/commitFormatter.ts
  7. +7
    -6
      src/git/git.ts
  8. +165
    -20
      src/git/gitService.ts
  9. +9
    -45
      src/git/models/commit.ts
  10. +1
    -1
      src/views/nodes/commitFileNode.ts
  11. +1
    -1
      src/views/nodes/statusFileNode.ts

+ 114
- 54
src/annotations/annotations.ts View File

@ -17,6 +17,8 @@ import {
GitBlameCommit,
GitCommit,
GitDiffHunkLine,
GitLogCommit,
GitService,
GitUri
} from '../git/gitService';
import { Objects, Strings } from '../system';
@ -62,74 +64,121 @@ export class Annotations {
commit: GitBlameCommit,
uri: GitUri,
editorLine: number
): Promise<MarkdownString | undefined>;
static async changesHoverMessage(
commit: GitLogCommit,
uri: GitUri,
editorLine: number,
hunkLine: GitDiffHunkLine
): Promise<MarkdownString | undefined>;
static async changesHoverMessage(
commit: GitBlameCommit | GitLogCommit,
uri: GitUri,
editorLine: number,
hunkLine?: GitDiffHunkLine
): Promise<MarkdownString | undefined> {
let ref;
if (commit.isUncommitted) {
if (uri.isUncommittedStaged) {
ref = uri.sha;
const documentRef = uri.sha;
if (commit instanceof GitBlameCommit) {
// TODO: Figure out how to optimize this
let ref;
if (commit.isUncommitted) {
if (GitService.isUncommittedStaged(documentRef)) {
ref = documentRef;
}
}
else {
ref = commit.sha;
}
}
else {
ref = commit.sha;
}
const line = editorLine + 1;
const commitLine = commit.lines.find(l => l.line === line) || commit.lines[0];
const line = editorLine + 1;
const commitLine = commit.lines.find(l => l.line === line) || commit.lines[0];
let originalFileName = commit.originalFileName;
if (originalFileName === undefined) {
if (uri.fsPath !== commit.uri.fsPath) {
originalFileName = commit.fileName;
let originalFileName = commit.originalFileName;
if (originalFileName === undefined) {
if (uri.fsPath !== commit.uri.fsPath) {
originalFileName = commit.fileName;
}
}
}
const commitEditorLine = commitLine.originalLine - 1;
const hunkLine = await Container.git.getDiffForLine(uri, commitEditorLine, ref, undefined, originalFileName);
return this.changesHoverDiffMessage(commit, uri, hunkLine, commitEditorLine);
}
editorLine = commitLine.originalLine - 1;
hunkLine = await Container.git.getDiffForLine(uri, editorLine, ref, undefined, originalFileName);
// If we didn't find a diff & ref is undefined (meaning uncommitted), check for a staged diff
if (hunkLine === undefined && ref === undefined) {
hunkLine = await Container.git.getDiffForLine(
uri,
editorLine,
undefined,
GitService.uncommittedStagedSha,
originalFileName
);
}
}
static changesHoverDiffMessage(
commit: GitCommit,
uri: GitUri,
hunkLine: GitDiffHunkLine | undefined,
editorLine?: number
): MarkdownString | undefined {
if (hunkLine === undefined || commit.previousSha === undefined) return undefined;
const diff = this.getDiffFromHunkLine(hunkLine);
let message: string;
let message;
let previous;
let current;
if (commit.isUncommitted) {
if (uri.isUncommittedStaged) {
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(
commit,
editorLine
)} "Open Changes") &nbsp; ${GlyphChars.Dash} &nbsp; [\`${
commit.previousShortSha
}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.previousSha!
)} "Show Commit Details") ${GlyphChars.ArrowLeftRightLong} _${uri.shortSha}_\n${diff}`;
}
else {
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(
commit,
editorLine
)} "Open Changes") &nbsp; ${GlyphChars.Dash} &nbsp; _uncommitted changes_\n${diff}`;
const diffUris = await commit.getPreviousLineDiffUris(uri, editorLine, documentRef);
if (diffUris === undefined || diffUris.previous === undefined) {
return undefined;
}
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs({
lhs: {
sha: diffUris.previous.sha || '',
uri: diffUris.previous.documentUri()
},
rhs: {
sha: diffUris.current.sha || '',
uri: diffUris.current.documentUri()
},
repoPath: commit.repoPath,
line: editorLine
})} "Open Changes")`;
previous =
diffUris.previous.sha === undefined || diffUris.previous.isUncommitted
? `_${GitService.shortenSha(diffUris.previous.sha, {
working: 'Working Tree'
})}_`
: `[\`${GitService.shortenSha(
diffUris.previous.sha || ''
)}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
diffUris.previous.sha || ''
)} "Show Commit Details")`;
current =
diffUris.current.sha === undefined || diffUris.current.isUncommitted
? `_${GitService.shortenSha(diffUris.current.sha, {
working: 'Working Tree'
})}_`
: `[\`${GitService.shortenSha(
diffUris.current.sha || ''
)}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
diffUris.current.sha || ''
)} "Show Commit Details")`;
}
else {
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(
commit,
editorLine
)} "Open Changes") &nbsp; ${GlyphChars.Dash} &nbsp; [\`${
commit.previousShortSha
}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.previousSha!)} "Show Commit Details") ${
GlyphChars.ArrowLeftRightLong
} [\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(commit, editorLine)} "Open Changes")`;
previous = `[\`${commit.previousShortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.previousSha!
)} "Show Commit Details")`;
current = `[\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.sha
)} "Show Commit Details")\n${diff}`;
)} "Show Commit Details")`;
}
message += ` &nbsp; ${GlyphChars.Dash} &nbsp; ${previous} &nbsp;${
GlyphChars.ArrowLeftRightLong
}&nbsp; ${current}\n${diff}`;
const markdown = new MarkdownString(message);
markdown.isTrusted = true;
return markdown;
@ -140,14 +189,15 @@ export class Annotations {
uri: GitUri,
editorLine: number,
dateFormat: string | null,
annotationType?: FileAnnotationType
annotationType: FileAnnotationType | undefined
): Promise<MarkdownString> {
if (dateFormat === null) {
dateFormat = 'MMMM Do, YYYY h:mma';
}
const [presence, remotes] = await Promise.all([
const [presence, previousLineDiffUris, remotes] = await Promise.all([
Container.vsls.getContactPresence(commit.email),
commit.isUncommitted ? commit.getPreviousLineDiffUris(uri, editorLine, uri.sha) : undefined,
Container.git.getRemotes(commit.repoPath)
]);
@ -158,6 +208,7 @@ export class Annotations {
line: editorLine,
markdown: true,
presence: presence,
previousLineDiffUris: previousLineDiffUris,
remotes: remotes
})
);
@ -274,13 +325,22 @@ export class Annotations {
static trailing(
commit: GitCommit,
// uri: GitUri,
// editorLine: number,
format: string,
dateFormat: string | null,
scrollable: boolean = true
): Partial<DecorationOptions> {
// TODO: Enable this once there is better caching
// let diffUris;
// if (commit.isUncommitted) {
// diffUris = await commit.getPreviousLineDiffUris(uri, editorLine, uri.sha);
// }
const message = CommitFormatter.fromTemplate(format, commit, {
truncateMessageAtNewLine: true,
dateFormat: dateFormat
dateFormat: dateFormat,
// previousLineDiffUris: diffUris,
truncateMessageAtNewLine: true
});
return {

+ 3
- 0
src/annotations/lineAnnotationController.ts View File

@ -185,6 +185,8 @@ export class LineAnnotationController implements Disposable {
const decoration = Annotations.trailing(
state.commit,
// await GitUri.fromUri(editor.document.uri),
// l,
cfg.format,
cfg.dateFormat === null ? Container.config.defaultDateFormat : cfg.dateFormat,
cfg.scrollable
@ -192,6 +194,7 @@ export class LineAnnotationController implements Disposable {
decoration.range = editor.document.validateRange(
new Range(l, Number.MAX_SAFE_INTEGER, l, Number.MAX_SAFE_INTEGER)
);
decorations.push(decoration);
}

+ 1
- 1
src/annotations/recentChangesAnnotationProvider.ts View File

@ -73,7 +73,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
}
if (cfg.hovers.annotations.changes) {
message = Annotations.changesHoverDiffMessage(commit, this._uri, hunkLine, count);
message = await Annotations.changesHoverMessage(commit, this._uri, count, hunkLine);
if (message === undefined) continue;
}
}

+ 3
- 57
src/commands/diffLineWithPrevious.ts View File

@ -31,66 +31,12 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand {
const gitUri = args.commit !== undefined ? GitUri.fromCommit(args.commit) : await GitUri.fromUri(uri);
if (gitUri.sha === undefined || gitUri.isUncommitted) {
const blame =
editor && editor.document.isDirty
? await Container.git.getBlameForLineContents(gitUri, args.line, editor.document.getText())
: await Container.git.getBlameForLine(gitUri, args.line);
if (blame === undefined) {
return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
}
// If the line is uncommitted, change the previous commit
if (blame.commit.isUncommitted) {
// Since there could be a change in the line number, update it
args.line = blame.line.originalLine - 1;
try {
const previous = await Container.git.getPreviousUri(
gitUri.repoPath!,
gitUri,
gitUri.sha,
0,
args.line
);
if (previous === undefined) {
return Messages.showCommitHasNoPreviousCommitWarningMessage();
}
const diffArgs: DiffWithCommandArgs = {
repoPath: gitUri.repoPath!,
lhs: {
sha: previous.sha || '',
uri: previous.documentUri()
},
rhs: {
sha: gitUri.sha || '',
uri: gitUri.documentUri()
},
line: args.line,
showOptions: args.showOptions
};
return commands.executeCommand(Commands.DiffWith, diffArgs);
}
catch (ex) {
Logger.error(
ex,
'DiffLineWithPreviousCommand',
`getPreviousUri(${gitUri.repoPath}, ${gitUri.fsPath}, ${gitUri.sha})`
);
return Messages.showGenericErrorMessage('Unable to open compare');
}
}
}
try {
const diffUris = await Container.git.getPreviousDiffUris(
const diffUris = await Container.git.getPreviousLineDiffUris(
gitUri.repoPath!,
gitUri,
gitUri.sha,
0,
args.line
args.line,
gitUri.sha
);
if (diffUris === undefined || diffUris.previous === undefined) {

+ 1
- 1
src/commands/externalDiff.ts View File

@ -77,7 +77,7 @@ export class ExternalDiffCommand extends Command {
args.files = [
{
uri: GitUri.fromFile(context.node.file, context.node.file.repoPath || context.node.repoPath),
staged: context.node.commit.isStagedUncommitted || context.node.file.indexStatus !== undefined,
staged: context.node.commit.isUncommittedStaged || context.node.file.indexStatus !== undefined,
ref1: ref1,
ref2: ref2
}

+ 51
- 14
src/git/formatters/commitFormatter.ts View File

@ -10,10 +10,8 @@ import {
import { DateStyle, FileAnnotationType } from '../../configuration';
import { GlyphChars } from '../../constants';
import { Container } from '../../container';
import { GitCommit, GitCommitType, GitLogCommit, GitRemote, GitService, GitUri } from '../gitService';
import { Strings } from '../../system';
import { GitUri } from '../gitUri';
import { GitCommit, GitCommitType } from '../models/commit';
import { GitLogCommit, GitRemote } from '../models/models';
import { FormatOptions, Formatter } from './formatter';
import * as emojis from '../../emojis.json';
import { ContactPresence } from '../../vsls/vsls';
@ -32,6 +30,7 @@ export interface CommitFormatOptions extends FormatOptions {
line?: number;
markdown?: boolean;
presence?: ContactPresence;
previousLineDiffUris?: { current: GitUri; previous: GitUri | undefined };
remotes?: GitRemote[];
truncateMessageAtNewLine?: boolean;
@ -164,15 +163,47 @@ export class CommitFormatter extends Formatter {
}
get commands() {
if (!this._options.markdown) return emptyStr;
let commands;
if (this._item.isUncommitted) {
return `\`${
this._item.shortSha === 'Working Tree'
? this._padOrTruncate('00000000', this._options.tokenOptions.id)
: this.id
}\``;
const { previousLineDiffUris: diffUris } = this._options;
if (diffUris !== undefined && diffUris.previous !== undefined) {
commands = `\`${this._padOrTruncate(
GitService.shortenSha(
GitService.isUncommittedStaged(diffUris.current.sha)
? diffUris.current.sha
: GitService.uncommittedSha
)!,
this._options.tokenOptions.id
)}\``;
commands += ` **[\`${GlyphChars.MuchLessThan}\`](${DiffWithCommand.getMarkdownCommandArgs({
lhs: {
sha: diffUris.previous.sha || '',
uri: diffUris.previous.documentUri()
},
rhs: {
sha: diffUris.current.sha || '',
uri: diffUris.current.documentUri()
},
repoPath: this._item.repoPath,
line: this._options.line
})} "Open Changes")** `;
}
else {
commands = `\`${this._padOrTruncate(
GitService.shortenSha(
this._item.isUncommittedStaged ? GitService.uncommittedStagedSha : GitService.uncommittedSha
)!,
this._options.tokenOptions.id
)}\``;
}
return commands;
}
let commands = `[\`${this.id}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commands = `[\`${this.id}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
this._item.sha
)} "Show Commit Details") `;
@ -247,11 +278,17 @@ export class CommitFormatter extends Formatter {
get message() {
let message: string;
if (this._item.isStagedUncommitted) {
message = 'Staged changes';
}
else if (this._item.isUncommitted) {
message = 'Uncommitted changes';
if (this._item.isUncommitted) {
if (
this._item.isUncommittedStaged ||
(this._options.previousLineDiffUris !== undefined &&
this._options.previousLineDiffUris.current.isUncommittedStaged)
) {
message = 'Staged changes';
}
else {
message = 'Uncommitted changes';
}
}
else {
if (this._options.truncateMessageAtNewLine) {

+ 7
- 6
src/git/git.ts View File

@ -26,9 +26,10 @@ const slash = '/';
// This is a root sha of all git repo's if using sha1
const rootSha = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
const GitErrors = {
export const GitErrors = {
badRevision: /bad revision '(.*?)'/i,
notAValidObjectName: /Not a valid object name/i
notAValidObjectName: /Not a valid object name/i,
invalidLineCount: /file .+? has only \d+ lines/i
};
const GitWarnings = {
@ -258,14 +259,14 @@ export class Git {
static shortenSha(
ref: string | undefined,
{
stagedUncommitted = 'Index',
uncommitted = 'Working Tree',
uncommittedStaged: uncommittedStaged = 'Index',
working = emptyStr
}: { stagedUncommitted?: string; uncommitted?: string; working?: string } = {}
}: { uncommittedStaged?: string; uncommitted?: string; working?: string } = {}
) {
if (ref == null || ref.length === 0) return working;
if (Git.isUncommitted(ref)) {
return Git.isUncommittedStaged(ref) ? stagedUncommitted : uncommitted;
return Git.isUncommittedStaged(ref) ? uncommittedStaged : uncommitted;
}
if (!Git.isShaLike(ref)) return ref;
@ -749,7 +750,7 @@ export class Git {
// static log__shortstat(repoPath: string, options: { ref?: string }) {
// const params = ['log', '--shortstat', '--oneline'];
// if (options.ref && !Git.isStagedUncommitted(options.ref)) {
// if (options.ref && !Git.isUncommittedStaged(options.ref)) {
// params.push(options.ref);
// }
// return git<string>({ cwd: repoPath }, ...params, '--');

+ 165
- 20
src/git/gitService.ts View File

@ -45,6 +45,7 @@ import {
GitDiffHunkLine,
GitDiffParser,
GitDiffShortStat,
GitErrors,
GitFile,
GitLog,
GitLogCommit,
@ -1210,12 +1211,7 @@ export class GitService implements Disposable {
originalFileName?: string
): Promise<GitDiffHunkLine | undefined> {
try {
let diff = await this.getDiffForFile(uri, ref1, ref2, originalFileName);
// If we didn't find a diff & ref1 is undefined (meaning uncommitted), check for a staged diff
if (diff === undefined && ref1 === undefined) {
diff = await this.getDiffForFile(uri, Git.uncommittedStagedSha, ref2, originalFileName);
}
const diff = await this.getDiffForFile(uri, ref1, ref2, originalFileName);
if (diff === undefined) return undefined;
const line = editorLine + 1;
@ -1727,34 +1723,155 @@ export class GitService implements Disposable {
repoPath: string,
uri: Uri,
ref: string | undefined,
skip: number = 0,
editorLine?: number
skip: number = 0
): Promise<{ current: GitUri; previous: GitUri | undefined } | undefined> {
if (ref === GitService.deletedOrMissingSha) return undefined;
const fileName = GitUri.relativeTo(uri, repoPath);
// If the ref is missing (i.e. working tree), check the file status to see if there is anything staged
if ((ref === undefined || ref.length === 0) && editorLine === undefined) {
// If we are at the working tree (i.e. no ref), we need to dig deeper to figure out where to go
if (ref === undefined || ref.length === 0) {
// First, check the file status to see if there is anything staged
const status = await Container.git.getStatusForFile(repoPath, fileName);
if (status !== undefined) {
// If the file is staged, diff with the staged version
// If the file is staged with working changes, diff working with staged (index)
// If the file is staged without working changes, diff staged with HEAD
if (status.indexStatus !== undefined) {
// Backs up to get to HEAD
if (status.workingTreeStatus === undefined) {
skip++;
}
if (skip === 0) {
// Diff working with staged
return {
current: GitUri.fromFile(fileName, repoPath, ref),
current: GitUri.fromFile(fileName, repoPath, undefined),
previous: GitUri.fromFile(fileName, repoPath, GitService.uncommittedStagedSha)
};
}
return {
// Diff staged with HEAD (or prior if more skips)
current: GitUri.fromFile(fileName, repoPath, GitService.uncommittedStagedSha),
previous: await this.getPreviousUri(repoPath, uri, ref, skip - 1, editorLine)
previous: await this.getPreviousUri(repoPath, uri, ref, skip - 1)
};
}
}
}
else if (Git.isUncommittedStaged(ref)) {
// If we are at the index (staged), diff staged with HEAD
else if (GitService.isUncommittedStaged(ref)) {
const current =
skip === 0
? GitUri.fromFile(fileName, repoPath, ref)
: (await this.getPreviousUri(repoPath, uri, undefined, skip - 1))!;
if (current.sha === GitService.deletedOrMissingSha) return undefined;
return {
current: current,
previous: await this.getPreviousUri(repoPath, uri, undefined, skip)
};
}
// If we are at a commit, diff commit with previous
const current =
skip === 0
? GitUri.fromFile(fileName, repoPath, ref)
: (await this.getPreviousUri(repoPath, uri, ref, skip - 1))!;
if (current.sha === GitService.deletedOrMissingSha) return undefined;
return {
current: current,
previous: await this.getPreviousUri(repoPath, uri, ref, skip)
};
}
@log()
async getPreviousLineDiffUris(
repoPath: string,
uri: Uri,
editorLine: number,
ref: string | undefined,
skip: number = 0
): Promise<{ current: GitUri; previous: GitUri | undefined } | undefined> {
if (ref === GitService.deletedOrMissingSha) return undefined;
let fileName = GitUri.relativeTo(uri, repoPath);
// If we are at the working tree (i.e. no ref), we need to dig deeper to figure out where to go
if (ref === undefined || ref.length === 0) {
// First, check the blame on the current line to see if there are any working/staged changes
const gitUri = new GitUri(uri, repoPath);
const document = await workspace.openTextDocument(uri);
const blameLine = document.isDirty
? await this.getBlameForLineContents(gitUri, editorLine, document.getText())
: await this.getBlameForLine(gitUri, editorLine);
if (blameLine === undefined) return undefined;
// If line is uncommitted, we need to dig deeper to figure out where to go (because blame can't be trusted)
if (blameLine.commit.isUncommitted) {
// If the document is dirty (unsaved), use the status to determine where to go
if (document.isDirty) {
// Check the file status to see if there is anything staged
const status = await Container.git.getStatusForFile(repoPath, fileName);
if (status !== undefined) {
// If the file is staged, diff working with staged (index)
// If the file is not staged, diff working with HEAD
if (status.indexStatus !== undefined) {
// Diff working with staged
return {
current: GitUri.fromFile(fileName, repoPath, undefined),
previous: GitUri.fromFile(fileName, repoPath, GitService.uncommittedStagedSha)
};
}
}
// Diff working with HEAD (or prior if more skips)
return {
current: GitUri.fromFile(fileName, repoPath, undefined),
previous: await this.getPreviousUri(repoPath, uri, undefined, skip, editorLine)
};
}
// First, check if we have a diff in the working tree
let hunkLine = await this.getDiffForLine(gitUri!, editorLine, undefined);
if (hunkLine === undefined) {
// Next, check if we have a diff in the index (staged)
hunkLine = await this.getDiffForLine(
gitUri!,
editorLine,
undefined,
GitService.uncommittedStagedSha
);
if (hunkLine !== undefined) {
ref = GitService.uncommittedStagedSha;
}
else {
skip++;
}
}
}
// If line is committed, diff with line ref with previous
else {
ref = blameLine.commit.sha;
fileName = blameLine.commit.fileName || blameLine.commit.originalFileName || fileName;
uri = GitUri.resolveToUri(fileName, repoPath);
editorLine = blameLine.line.originalLine - 1;
}
const current =
skip === 0
? GitUri.fromFile(fileName, repoPath, ref)
: (await this.getPreviousUri(repoPath, uri, ref, skip - 1, editorLine))!;
if (current.sha === GitService.deletedOrMissingSha) return undefined;
return {
current: current,
previous: await this.getPreviousUri(repoPath, uri, ref, skip, editorLine)
};
}
else if (GitService.isUncommittedStaged(ref)) {
const current =
skip === 0
? GitUri.fromFile(fileName, repoPath, ref)
@ -1788,6 +1905,9 @@ export class GitService implements Disposable {
editorLine?: number
): Promise<GitUri | undefined> {
if (ref === GitService.deletedOrMissingSha) return undefined;
const cc = Logger.getCorrelationContext();
if (ref === GitService.uncommittedSha) {
ref = undefined;
}
@ -1797,11 +1917,35 @@ export class GitService implements Disposable {
}
const fileName = GitUri.relativeTo(uri, repoPath);
const data = await Git.log__file(repoPath, fileName, ref, {
format: GitLogParser.simpleFormat,
maxCount: skip + 1,
startLine: editorLine !== undefined ? editorLine + 1 : undefined
});
// TODO: Add caching
let data;
try {
data = await Git.log__file(repoPath, fileName, ref, {
format: GitLogParser.simpleFormat,
maxCount: skip + 1,
startLine: editorLine !== undefined ? editorLine + 1 : undefined
});
}
catch (ex) {
// If the line count is invalid just fallback to the most recent commit
if (
(ref === undefined || GitService.isUncommittedStaged(ref)) &&
GitErrors.invalidLineCount.test(ex.message)
) {
if (ref === undefined) {
const status = await Container.git.getStatusForFile(repoPath, fileName);
if (status !== undefined && status.indexStatus !== undefined) {
return GitUri.fromFile(fileName, repoPath, GitService.uncommittedStagedSha);
}
}
ref = await Git.log__file_recent(repoPath, fileName);
return GitUri.fromFile(fileName, repoPath, ref || GitService.deletedOrMissingSha);
}
Logger.error(ex, cc);
throw ex;
}
if (data == null || data.length === 0) throw new Error('File has no history');
const [previousRef, file] = GitLogParser.parseSimple(data, skip, editorLine !== undefined ? ref : undefined);
@ -2156,6 +2300,7 @@ export class GitService implements Disposable {
return GitUri.resolveToUri(data, repoPath);
}
// TODO: Add caching
// Get the most recent commit for this file name
ref = await Git.log__file_recent(repoPath, fileName, {
similarityThreshold: Container.config.advanced.similarityThreshold
@ -2451,7 +2596,7 @@ export class GitService implements Disposable {
{
deletedOrMissing = '(deleted)',
...strings
}: { deletedOrMissing?: string; stagedUncommitted?: string; uncommitted?: string; working?: string } = {}
}: { deletedOrMissing?: string; uncommitted?: string; uncommittedStaged?: string; working?: string } = {}
) {
if (ref === GitService.deletedOrMissingSha) return deletedOrMissing;

+ 9
- 45
src/git/models/commit.ts View File

@ -93,13 +93,13 @@ export abstract class GitCommit {
}
@memoize()
get isStagedUncommitted(): boolean {
return Git.isUncommittedStaged(this.sha);
get isUncommitted(): boolean {
return Git.isUncommitted(this.sha);
}
@memoize()
get isUncommitted(): boolean {
return Git.isUncommitted(this.sha);
get isUncommittedStaged(): boolean {
return Git.isUncommittedStaged(this.sha);
}
get previousFileSha(): string {
@ -119,51 +119,15 @@ export abstract class GitCommit {
return GitUri.resolveToUri(this.fileName, this.repoPath);
}
// @memoize()
// getFileStatus() {
// if (!this.isFile) return Promise.resolve(undefined);
// return Container.git.getStatusForFile(this.repoPath, this.fileName);
// }
// @memoize(
// (uri: Uri, ref: string | undefined, editorLine?: number) =>
// `${uri.toString(true)}|${ref || ''}|${editorLine || ''}`
// )
getPreviousDiffUris(uri: Uri, ref: string | undefined, editorLine?: number) {
@memoize<GitCommit['getPreviousLineDiffUris']>(
(uri, editorLine, ref) => `${uri.toString(true)}|${editorLine || ''}|${ref || ''}`
)
getPreviousLineDiffUris(uri: Uri, editorLine: number, ref: string | undefined) {
if (!this.isFile) return Promise.resolve(undefined);
return Container.git.getPreviousDiffUris(this.repoPath, uri, ref, 0, editorLine);
return Container.git.getPreviousLineDiffUris(this.repoPath, uri, editorLine, ref);
}
// private _previousUriPromise: Promise<GitUri | undefined> | undefined;
// getPreviousUri(staged: boolean = false) {
// if (!this.isFile) return Promise.resolve(undefined);
// if (!this.isUncommitted && this.previousSha !== undefined && !GitService.isShaParent(this.previousSha)) {
// return Promise.resolve(this.toGitUri(true));
// }
// if (this._previousUriPromise === undefined) {
// this._previousUriPromise = this._getPreviousUriCore(staged);
// }
// return this._previousUriPromise;
// }
// private async _getPreviousUriCore(staged: boolean) {
// if (!staged && !GitService.isStagedUncommitted(this.sha)) {
// const status = await this.getFileStatus();
// if (status !== undefined) {
// // If the file is staged, diff with the staged version
// if (status.indexStatus !== undefined) {
// return GitUri.fromFile(this.fileName, this.repoPath, GitService.stagedUncommittedSha);
// }
// }
// }
// return Container.git.getPreviousUri(this.repoPath, this.uri, this.sha);
// }
@memoize()
getWorkingUri(): Promise<Uri | undefined> {
if (!this.isFile) return Promise.resolve(undefined);

+ 1
- 1
src/views/nodes/commitFileNode.ts View File

@ -150,7 +150,7 @@ export class CommitFileNode extends ViewRefFileNode {
protected get resourceType(): string {
if (!this.commit.isUncommitted) return ResourceType.CommitFile;
return this.commit.isStagedUncommitted ? `${ResourceType.File}+staged` : `${ResourceType.File}+unstaged`;
return this.commit.isUncommittedStaged ? `${ResourceType.File}+staged` : `${ResourceType.File}+unstaged`;
}
private _tooltip: string | undefined;

+ 1
- 1
src/views/nodes/statusFileNode.ts View File

@ -23,7 +23,7 @@ export class StatusFileNode extends ViewNode {
super(GitUri.fromFile(file, repoPath, 'HEAD'), view, parent);
for (const c of this.commits) {
if (c.isStagedUncommitted) {
if (c.isUncommittedStaged) {
this._hasStagedChanges = true;
}
else if (c.isUncommitted) {

Loading…
Cancel
Save