From 7bb48ae00b07db2e79fe46f4b38bf71141f8c95f Mon Sep 17 00:00:00 2001 From: Eric Amodio <eamodio@gmail.com> Date: Wed, 11 Oct 2017 18:11:22 -0400 Subject: [PATCH] Fixes stashed file diffs --- CHANGELOG.md | 2 ++ src/commands/diffLineWithWorking.ts | 8 +++++++- src/git/git.ts | 9 +++++---- src/git/models/commit.ts | 22 ++++++++++++++++------ src/git/models/logCommit.ts | 26 ++++++++++++++++++++++++++ src/git/parsers/stashParser.ts | 2 +- src/views/stashFileNode.ts | 10 +++++----- src/views/stashNode.ts | 2 +- 8 files changed, 63 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5eaf02c..67489f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed +- Fixes issue where diffs for stashed files were often wrong (missing) ## [5.6.0] - 2017-10-11 ### Added diff --git a/src/commands/diffLineWithWorking.ts b/src/commands/diffLineWithWorking.ts index 1df8f89..6c65b3f 100644 --- a/src/commands/diffLineWithWorking.ts +++ b/src/commands/diffLineWithWorking.ts @@ -43,7 +43,13 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand { args.commit = blame.commit; // If the line is uncommitted, find the previous commit if (args.commit.isUncommitted) { - args.commit = new GitCommit(args.commit.type, args.commit.repoPath, args.commit.previousSha!, args.commit.previousFileName!, args.commit.author, args.commit.date, args.commit.message); + args.commit = args.commit.with({ + sha: args.commit.previousSha!, + fileName: args.commit.previousFileName!, + originalFileName: null, + previousSha: null, + previousFileName: null + }); args.line = blame.line.line + 1; } } diff --git a/src/git/git.ts b/src/git/git.ts index e2b252b..6c4237b 100644 --- a/src/git/git.ts +++ b/src/git/git.ts @@ -94,8 +94,8 @@ function gitCommandDefaultErrorHandler(ex: Error, options: GitCommandOptions, .. export class Git { - static shaRegex = /^[0-9a-f]{40}( -)?$/; - static uncommittedRegex = /^[0]+$/; + static shaRegex = /^[0-9a-f]{40}(\^[0-9]*?)??( -)?$/; + static uncommittedRegex = /^[0]{40}(\^[0-9]*?)??$/; static gitInfo(): IGit { return git; @@ -156,6 +156,9 @@ export class Git { } static shortenSha(sha: string) { + const index = sha.indexOf('^'); + // This is lame, but assume there is only 1 character after the ^ + if (index > 6) return `${sha.substring(0, 6)}${sha.substring(index)}`; return sha.substring(0, 8); } @@ -385,8 +388,6 @@ export class Git { static async show(repoPath: string | undefined, fileName: string, branchOrSha: string, encoding?: string) { const [file, root] = Git.splitPath(fileName, repoPath); - branchOrSha = branchOrSha.replace('^', ''); - if (Git.isUncommitted(branchOrSha)) throw new Error(`sha=${branchOrSha} is uncommitted`); const opts = { cwd: root, encoding: encoding || defaultEncoding, overrideErrorHandling: true }; diff --git a/src/git/models/commit.ts b/src/git/models/commit.ts index 51bccb6..043f883 100644 --- a/src/git/models/commit.ts +++ b/src/git/models/commit.ts @@ -98,11 +98,21 @@ export class GitCommit { return GitUri.getFormattedPath(this.fileName, separator); } - with(changes: { type?: GitCommitType, fileName?: string, sha?: string, originalFileName?: string, previousFileName?: string, previousSha?: string }) { - return new GitCommit(changes.type || this.type, this.repoPath, - changes.sha || this.sha, changes.fileName || this.fileName, - this.author, this.date, this.message, - changes.originalFileName || this.originalFileName, - changes.previousSha || this.previousSha, changes.previousFileName || this.previousFileName); + with(changes: { type?: GitCommitType, sha?: string, fileName?: string, originalFileName?: string | null, previousFileName?: string | null, previousSha?: string | null }): GitCommit { + return new GitCommit(changes.type || this.type, + this.repoPath, + changes.sha || this.sha, + changes.fileName || this.fileName, + this.author, + this.date, + this.message, + this.getChangedValue(changes.originalFileName, this.originalFileName), + this.getChangedValue(changes.previousSha, this.previousSha), + this.getChangedValue(changes.previousFileName, this.previousFileName)); + } + + protected getChangedValue<T>(change: T | null | undefined, original: T | undefined): T | undefined { + if (change === undefined) return original; + return change !== null ? change : undefined; } } \ No newline at end of file diff --git a/src/git/models/logCommit.ts b/src/git/models/logCommit.ts index ca7adf7..4b29552 100644 --- a/src/git/models/logCommit.ts +++ b/src/git/models/logCommit.ts @@ -68,4 +68,30 @@ export class GitLogCommit extends GitCommit { const changed = this.fileStatuses.filter(_ => _.status !== 'A' && _.status !== '?' && _.status !== 'D').length; return `+${added} ~${changed} -${deleted}`; } + + toFileCommit(status: IGitStatusFile): GitLogCommit { + return this.with({ + type: GitCommitType.File, + fileName: status.fileName, + originalFileName: status.originalFileName, + previousFileName: status.originalFileName || status.fileName, + status: status.status, + fileStatuses: null + }); + } + + with(changes: { type?: GitCommitType, sha?: string, fileName?: string, originalFileName?: string | null, previousFileName?: string | null, previousSha?: string | null, status?: GitStatusFileStatus, fileStatuses?: IGitStatusFile[] | null }): GitLogCommit { + return new GitLogCommit(changes.type || this.type, + this.repoPath, + changes.sha || this.sha, + changes.fileName || this.fileName, + this.author, + this.date, + this.message, + changes.status || this.status, + this.getChangedValue(changes.fileStatuses, this.fileStatuses), + this.getChangedValue(changes.originalFileName, this.originalFileName), + this.getChangedValue(changes.previousSha, this.previousSha), + this.getChangedValue(changes.previousFileName, this.previousFileName)); + } } \ No newline at end of file diff --git a/src/git/parsers/stashParser.ts b/src/git/parsers/stashParser.ts index 41ae97f..27f01e2 100644 --- a/src/git/parsers/stashParser.ts +++ b/src/git/parsers/stashParser.ts @@ -24,7 +24,7 @@ export class GitStashParser { let commit = commits.get(entry.sha); if (commit === undefined) { - commit = new GitStashCommit(entry.stashName, repoPath, entry.sha, entry.fileNames, new Date(entry.date! as any * 1000), entry.summary, undefined, entry.fileStatuses) as GitStashCommit; + commit = new GitStashCommit(entry.stashName, repoPath, entry.sha, entry.fileNames, new Date(entry.date! as any * 1000), entry.summary, undefined, entry.fileStatuses, undefined, `${entry.sha}^1`) as GitStashCommit; commits.set(entry.sha, commit); } } diff --git a/src/views/stashFileNode.ts b/src/views/stashFileNode.ts index ca8b05b..824eaf6 100644 --- a/src/views/stashFileNode.ts +++ b/src/views/stashFileNode.ts @@ -1,7 +1,7 @@ 'use strict'; import { ExtensionContext } from 'vscode'; import { ResourceType } from './explorerNode'; -import { GitService, GitStashCommit, IGitStatusFile } from '../gitService'; +import { GitLogCommit, GitService, IGitStatusFile } from '../gitService'; import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode'; export class StashFileNode extends CommitFileNode { @@ -9,10 +9,10 @@ export class StashFileNode extends CommitFileNode { readonly resourceType: ResourceType = 'gitlens:stash-file'; constructor( - readonly status: IGitStatusFile, - readonly commit: GitStashCommit, - readonly context: ExtensionContext, - readonly git: GitService + status: IGitStatusFile, + commit: GitLogCommit, + context: ExtensionContext, + git: GitService ) { super(status, commit, context, git, CommitFileNodeDisplayAs.File); } diff --git a/src/views/stashNode.ts b/src/views/stashNode.ts index 03e48a1..a93a51f 100644 --- a/src/views/stashNode.ts +++ b/src/views/stashNode.ts @@ -31,7 +31,7 @@ export class StashNode extends ExplorerNode { } } - const children = statuses.map(s => new StashFileNode(s, this.commit, this.context, this.git)); + const children = statuses.map(s => new StashFileNode(s, this.commit.toFileCommit(s), this.context, this.git)); children.sort((a, b) => a.label!.localeCompare(b.label!)); return children; }