Browse Source

Deals with resolved vs unresolved previous shas

main
Eric Amodio 2 years ago
parent
commit
7fa3565940
15 changed files with 112 additions and 40 deletions
  1. +2
    -1
      src/commands/diffLineWithWorking.ts
  2. +6
    -4
      src/commands/diffWith.ts
  3. +2
    -3
      src/commands/externalDiff.ts
  4. +6
    -5
      src/commands/gitCommands.actions.ts
  5. +1
    -1
      src/commands/openCommitOnRemote.ts
  6. +10
    -7
      src/commands/openFileAtRevision.ts
  7. +6
    -1
      src/commands/openRevisionFile.ts
  8. +8
    -2
      src/env/node/git/localGitProvider.ts
  9. +3
    -3
      src/git/formatters/commitFormatter.ts
  10. +6
    -1
      src/git/gitProviderService.ts
  11. +41
    -3
      src/git/models/commit.ts
  12. +7
    -2
      src/hovers/hovers.ts
  13. +10
    -4
      src/premium/github/githubGitProvider.ts
  14. +2
    -1
      src/views/nodes/branchTrackingStatusNode.ts
  15. +2
    -2
      src/views/viewCommands.ts

+ 2
- 1
src/commands/diffLineWithWorking.ts View File

@ -58,7 +58,8 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
args.commit.repoPath,
);
} else {
lhsSha = args.commit.file!.previousSha ?? GitRevision.deletedOrMissing;
// Don't need to worry about verifying the previous sha, as the DiffWith command will
lhsSha = args.commit.unresolvedPreviousSha;
lhsUri = args.commit.file!.originalUri ?? args.commit.file!.uri;
}
} else {

+ 6
- 4
src/commands/diffWith.ts View File

@ -30,7 +30,7 @@ export class DiffWithCommand extends Command {
let args: DiffWithCommandArgs | GitCommit;
if (GitCommit.is(argsOrCommit)) {
const commit = argsOrCommit;
if (commit.file == null) {
if (commit.file == null || commit.unresolvedPreviousSha == null) {
debugger;
throw new Error('Commit has no file');
}
@ -52,7 +52,7 @@ export class DiffWithCommand extends Command {
args = {
repoPath: commit.repoPath,
lhs: {
sha: commit.file.previousSha ?? GitRevision.deletedOrMissing,
sha: commit.unresolvedPreviousSha,
uri: commit.file.originalUri ?? commit.file.uri,
},
rhs: {
@ -91,10 +91,12 @@ export class DiffWithCommand extends Command {
[args.lhs.sha, args.rhs.sha] = await Promise.all([
await this.container.git.resolveReference(args.repoPath, args.lhs.sha, args.lhs.uri, {
timeout: 100,
// If the ref looks like a sha, don't wait too long, since it should work
timeout: GitRevision.isSha(args.lhs.sha) ? 100 : undefined,
}),
await this.container.git.resolveReference(args.repoPath, args.rhs.sha, args.rhs.uri, {
timeout: 100,
// If the ref looks like a sha, don't wait too long, since it should work
timeout: GitRevision.isSha(args.rhs.sha) ? 100 : undefined,
}),
]);

+ 2
- 3
src/commands/externalDiff.ts View File

@ -38,9 +38,8 @@ export class ExternalDiffCommand extends Command {
args = { ...args };
if (isCommandContextViewNodeHasFileCommit(context)) {
const ref1 = GitRevision.isUncommitted(context.node.commit.previousSha)
? ''
: context.node.commit.previousSha;
const previousSha = await context.node.commit.getPreviousSha();
const ref1 = GitRevision.isUncommitted(previousSha) ? '' : previousSha;
const ref2 = context.node.commit.isUncommitted ? '' : context.node.commit.sha;
args.files = [

+ 6
- 5
src/commands/gitCommands.actions.ts View File

@ -219,7 +219,8 @@ export namespace GitActions {
files = commitOrFiles.files ?? [];
refs = {
repoPath: commitOrFiles.repoPath,
ref1: commitOrFiles.previousSha != null ? commitOrFiles.previousSha : GitRevision.deletedOrMissing,
// Don't need to worry about verifying the previous sha, as the DiffWith command will
ref1: commitOrFiles.unresolvedPreviousSha,
ref2: commitOrFiles.sha,
};
@ -361,8 +362,8 @@ export namespace GitActions {
const refs = GitCommit.is(commitOrRefs)
? {
repoPath: commitOrRefs.repoPath,
ref1:
commitOrRefs.previousSha != null ? commitOrRefs.previousSha : GitRevision.deletedOrMissing,
// Don't need to worry about verifying the previous sha, as the DiffWith command will
ref1: commitOrRefs.unresolvedPreviousSha,
ref2: commitOrRefs.sha,
}
: commitOrRefs;
@ -548,7 +549,7 @@ export namespace GitActions {
}
uri = Container.instance.git.getRevisionUri(
file.status === 'D' ? commit.previousSha : commit.sha,
file.status === 'D' ? (await commit.pan>getPreviousSha()) ?? GitRevision.deletedOrMissing : commit.sha,
file,
commit.repoPath,
);
@ -633,7 +634,7 @@ export namespace GitActions {
files = commitOrFiles.files ?? [];
repoPath = commitOrFiles.repoPath;
ref1 = commitOrFiles.sha;
ref2 = commitOrFiles.previousSha;
ref2 = await commitOrFiles.getPreviousSha();
} else {
files = commitOrFiles;
}

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

@ -82,7 +82,7 @@ export class OpenCommitOnRemoteCommand extends ActiveEditorCommand {
// If the line is uncommitted, use previous commit
args.sha = blame.commit.isUncommitted
? blame.commit.file!.previousSha ?? GitRevision.deletedOrMissing
? (await blame.commit.getPreviousSha()) ?? GitRevision.deletedOrMissing
: blame.commit.sha;
}

+ 10
- 7
src/commands/openFileAtRevision.ts View File

@ -60,18 +60,21 @@ export class OpenFileAtRevisionCommand extends ActiveEditorCommand {
const blame = await this.container.git.getBlameForLine(gitUri, editorLine);
if (blame != null) {
if (blame.commit.isUncommitted) {
const diffUris = await blame.commit.getPreviousComparisonUrisForLine(editorLine);
if (diffUris?.previous != null) {
args.revisionUri = this.container.git.getRevisionUri(diffUris.previous);
const comparisonUris = await blame.commit.getPreviousComparisonUrisForLine(editorLine);
if (comparisonUris?.previous != null) {
args.revisionUri = this.container.git.getRevisionUri(comparisonUris.previous);
} else {
void Messages.showCommitHasNoPreviousCommitWarningMessage(blame.commit);
return undefined;
}
} else if (blame?.commit.previousSha != null) {
args.revisionUri = this.container.git.getRevisionUri(blame.commit.getGitUri(true));
} else {
void Messages.showCommitHasNoPreviousCommitWarningMessage(blame.commit);
return undefined;
const previousSha = blame != null ? await blame?.commit.getPreviousSha() : undefined;
if (previousSha != null) {
args.revisionUri = this.container.git.getRevisionUri(blame.commit.getGitUri(true));
} else {
void Messages.showCommitHasNoPreviousCommitWarningMessage(blame.commit);
return undefined;
}
}
}
} catch (ex) {

+ 6
- 1
src/commands/openRevisionFile.ts View File

@ -2,6 +2,7 @@ import { TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { FileAnnotationType } from '../configuration';
import type { Container } from '../container';
import { GitUri } from '../git/gitUri';
import { GitRevision } from '../git/models';
import { Logger } from '../logger';
import { Messages } from '../messages';
import { ActiveEditorCommand, command, Commands, getCommandUri } from './common';
@ -39,7 +40,11 @@ export class OpenRevisionFileCommand extends ActiveEditorCommand {
args.revisionUri =
commit?.file?.status === 'D'
? this.container.git.getRevisionUri(commit.previousSha, commit.file, commit.repoPath)
? this.container.git.getRevisionUri(
(await commit.getPreviousSha()) ?? GitRevision.deletedOrMissing,
commit.file,
commit.repoPath,
)
: this.container.git.getRevisionUri(gitUri);
} else {
args.revisionUri = this.container.git.getRevisionUri(gitUri);

+ 8
- 2
src/env/node/git/localGitProvider.ts View File

@ -3502,12 +3502,18 @@ export class LocalGitProvider implements GitProvider, Disposable {
@log()
async resolveReference(repoPath: string, ref: string, pathOrUri?: string | Uri, options?: { timeout?: number }) {
if (!ref || ref === GitRevision.deletedOrMissing || GitRevision.isUncommitted(ref)) {
if (
!ref ||
ref === GitRevision.deletedOrMissing ||
(pathOrUri == null && GitRevision.isSha(ref)) ||
(pathOrUri != null && GitRevision.isUncommitted(ref))
) {
return ref;
}
if (pathOrUri == null) {
if (GitRevision.isSha(ref) || !GitRevision.isShaLike(ref) || ref.endsWith('^3')) return ref;
// If it doesn't look like a sha at all (e.g. branch name) or is a stash ref (^3) don't try to resolve it
if (!GitRevision.isShaLike(ref) || ref.endsWith('^3')) return ref;
return (await this.git.rev_parse__verify(repoPath, ref)) ?? ref;
}

+ 3
- 3
src/git/formatters/commitFormatter.ts View File

@ -319,10 +319,10 @@ export class CommitFormatter extends Formatter {
this._options.editor?.line,
)} "Open Changes with Previous Revision")`;
if (this._item.previousSha != null && this._item.file?.originalPath != null) {
if (this._item.file != null && this._item.unresolvedPreviousSha != null) {
const uri = Container.instance.git.getRevisionUri(
this._item.previousSha,
this._item.file.originalPath,
this._item.unresolvedPreviousSha,
this._item.file.originalPath ?? this._item.file?.path,
this._item.repoPath,
);
commands += `   [$(versions)](${OpenFileAtRevisionCommand.getMarkdownCommandArgs(

+ 6
- 1
src/git/gitProviderService.ts View File

@ -1845,7 +1845,12 @@ export class GitProviderService implements Disposable {
pathOrUri?: string | Uri,
options?: { timeout?: number },
) {
if (!ref || ref === GitRevision.deletedOrMissing || GitRevision.isUncommitted(ref)) {
if (
!ref ||
ref === GitRevision.deletedOrMissing ||
(pathOrUri == null && GitRevision.isSha(ref)) ||
(pathOrUri != null && GitRevision.isUncommitted(ref))
) {
return ref;
}

+ 41
- 3
src/git/models/commit.ts View File

@ -176,8 +176,11 @@ export class GitCommit implements GitRevisionReference {
return this._summary;
}
get previousSha(): string {
return this.file?.previousSha ?? this.parents[0] ?? `${this.sha}^`;
private _resolvedPreviousSha: string | undefined;
get unresolvedPreviousSha(): string {
if (this._resolvedPreviousSha != null) return this._resolvedPreviousSha;
if (this.file != null) return this.file.previousSha ?? `${this.sha}^`;
return this.parents[0] ?? `${this.sha}^`;
}
@gate()
@ -189,6 +192,7 @@ export class GitCommit implements GitRevisionReference {
// Check for any untracked files -- since git doesn't return them via `git stash list` :(
// See https://stackoverflow.com/questions/12681529/
this.stashName ? this.container.git.getCommit(this.repoPath, `${this.stashName}^3`) : undefined,
this.getPreviousSha(),
]);
if (commitResult.status !== 'fulfilled' || commitResult.value == null) return;
@ -403,7 +407,7 @@ export class GitCommit implements GitRevisionReference {
return new GitUri(this._file?.originalUri ?? uri, {
repoPath: this.repoPath,
sha: this.previousSha,
sha: this.unresolvedPreviousSha,
});
}
@ -422,6 +426,40 @@ export class GitCommit implements GitRevisionReference {
: Promise.resolve(undefined);
}
private _previousShaPromise: Promise<string | undefined> | undefined;
async getPreviousSha(): Promise<string | undefined> {
if (this._previousShaPromise == null) {
async function getCore(this: GitCommit) {
if (this.file != null) {
if (this.file.previousSha != null && GitRevision.isSha(this.file.previousSha)) {
return this.file.previousSha;
}
const sha = await this.container.git.resolveReference(
this.repoPath,
GitRevision.isUncommitted(this.sha, true) ? 'HEAD' : `${this.sha}^`,
this.file.originalPath ?? this.file.path,
);
return sha;
}
const parent = this.parents[0];
if (parent != null && GitRevision.isSha(parent)) return parent;
const sha = await this.container.git.resolveReference(
this.repoPath,
GitRevision.isUncommitted(this.sha, true) ? 'HEAD' : `${this.sha}^`,
);
return sha;
}
this._previousShaPromise = getCore.call(this).then(sha => (this._resolvedPreviousSha = sha));
}
return this._previousShaPromise;
}
@gate()
async isPushed(): Promise<boolean> {
return this.container.git.hasCommitBeenPushed(this.repoPath, this.ref);
}

+ 7
- 2
src/hovers/hovers.ts View File

@ -20,6 +20,8 @@ export namespace Hovers {
): Promise<MarkdownString | undefined> {
const documentRef = uri.sha;
let previousSha = null;
async function getDiff() {
if (commit.file == null) return undefined;
@ -30,7 +32,8 @@ export namespace Hovers {
ref = documentRef;
}
} else {
ref = commit.file.previousSha;
previousSha = await commit.getPreviousSha();
ref = previousSha;
if (ref == null) {
return `\`\`\`diff\n+ ${document.lineAt(editorLine).text}\n\`\`\``;
}
@ -115,7 +118,9 @@ export namespace Hovers {
editorLine,
)} "Open Changes")`;
const previousSha = commit.file?.previousSha;
if (previousSha === null) {
previousSha = await commit.getPreviousSha();
}
if (previousSha) {
previous = ` &nbsp;[$(git-commit) ${GitRevision.shorten(
previousSha,

+ 10
- 4
src/premium/github/githubGitProvider.ts View File

@ -2151,15 +2151,21 @@ export class GitHubGitProvider implements GitProvider, Disposable {
@log()
async resolveReference(repoPath: string, ref: string, pathOrUri?: string | Uri, _options?: { timeout?: number }) {
if (!ref || ref === GitRevision.deletedOrMissing || GitRevision.isUncommitted(ref)) {
if (
!ref ||
ref === GitRevision.deletedOrMissing ||
(pathOrUri == null && GitRevision.isSha(ref)) ||
(pathOrUri != null && GitRevision.isUncommitted(ref))
) {
return ref;
}
let relativePath;
if (pathOrUri == null) {
if (GitRevision.isSha(ref) || !GitRevision.isShaLike(ref) || ref.endsWith('^3')) return ref;
} else {
if (pathOrUri != null) {
relativePath = this.getRelativePath(pathOrUri, repoPath);
} else if (!GitRevision.isShaLike(ref) || ref.endsWith('^3')) {
// If it doesn't look like a sha at all (e.g. branch name) or is a stash ref (^3) don't try to resolve it
return ref;
}
const context = await this.ensureRepositoryContext(repoPath);

+ 2
- 1
src/views/nodes/branchTrackingStatusNode.ts View File

@ -80,7 +80,8 @@ export class BranchTrackingStatusNode extends ViewNode impleme
// Since the last commit when we are looking 'ahead' can have no previous (because of the range given) -- look it up
commits = [...log.commits.values()];
const commit = commits[commits.length - 1];
if (commit.previousSha == null) {
const previousSha = await commit.getPreviousSha();
if (previousSha == null) {
const previousLog = await this.view.container.git.getLog(this.uri.repoPath!, {
limit: 2,
ref: commit.sha,

+ 2
- 2
src/views/viewCommands.ts View File

@ -1063,7 +1063,7 @@ export class ViewCommands {
}
@debug()
private openRevision(
private async openRevision(
node:
| CommitFileNode
| FileRevisionAsCommitNode
@ -1094,7 +1094,7 @@ export class ViewCommands {
uri =
node.commit.file?.status === 'D'
? Container.instance.git.getRevisionUri(
node.commit.previousSha,
(await node.commit.getPreviousSha()) ?? GitRevision.deletedOrMissing,
node.commit.file.path,
node.commit.repoPath,
)

Loading…
Cancel
Save