Browse Source

Fixes #740 - opening untracked status files fails

Fixes diff w/ previous when there are no working file changes
Fixes broken status file commands
main
Eric Amodio 5 years ago
parent
commit
07ec5e68e6
9 changed files with 113 additions and 43 deletions
  1. +8
    -0
      CHANGELOG.md
  2. +1
    -1
      src/commands/diffWith.ts
  3. +19
    -3
      src/commands/diffWithPrevious.ts
  4. +7
    -3
      src/git/git.ts
  5. +24
    -5
      src/git/gitService.ts
  6. +9
    -7
      src/git/gitUri.ts
  7. +1
    -1
      src/quickpicks/commitQuickPick.ts
  8. +40
    -19
      src/views/nodes/statusFileNode.ts
  9. +4
    -4
      src/views/viewCommands.ts

+ 8
- 0
CHANGELOG.md View File

@ -4,6 +4,14 @@ 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 [#740](https://github.com/eamodio/vscode-gitlens/issues/740) - Opening untracked files from "files changed" section fails
- Fixes issue where the _Open Changes with Previous Revision_ command would compare the working file with HEAD even if there no working file changes (now it will compare HEAD with the previous commit)
- Fixes issue where the _Open Changes_, _Open Changes with Working File_, and _Open Revision_ commands on files in the "files changed" section of the _Repositories_ view would either fail or do nothing
## [9.7.2] - 2019-05-10
## Fixed

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

@ -136,7 +136,7 @@ export class DiffWithCommand extends ActiveEditorCommand {
let lhsSuffix = args.lhs.sha !== GitService.deletedOrMissingSha ? GitService.shortenSha(lhsSha) || '' : '';
if (lhs === undefined && args.rhs.sha.length === 0) {
if (rhs !== undefined) {
lhsSuffix = `not in ${lhsSuffix}`;
lhsSuffix = lhsSuffix.length === 0 ? '' : `not in ${lhsSuffix}`;
rhsSuffix = '';
}
else {

+ 19
- 3
src/commands/diffWithPrevious.ts View File

@ -1,10 +1,10 @@
'use strict';
import { commands, TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { Container } from '../container';
import { GitCommit, GitUri } from '../git/gitService';
import { GitCommit, GitService, GitUri } from '../git/gitService';
import { Logger } from '../logger';
import { Messages } from '../messages';
import { ActiveEditorCommand, command, CommandContext, Commands, getCommandUri } from './common';
import { ActiveEditorCommand, command, CommandContext, Commands, getCommandUri, openEditor } from './common';
import { DiffWithCommandArgs } from './diffWith';
import { UriComparer } from '../comparers';
@ -61,7 +61,23 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
);
if (diffUris === undefined || diffUris.previous === undefined) {
return Messages.showCommitHasNoPreviousCommitWarningMessage();
if (diffUris === undefined) return Messages.showCommitHasNoPreviousCommitWarningMessage();
// If we have no previous and the current is the working file, just open the working file
if (diffUris.current.sha === undefined) {
return openEditor(diffUris.current, args.showOptions);
}
if (!diffUris.current.isUncommittedStaged) {
return Messages.showCommitHasNoPreviousCommitWarningMessage();
}
// If we have no previous and the current is staged, then diff staged with missing
diffUris.previous = GitUri.fromFile(
diffUris.current.fileName,
diffUris.current.repoPath!,
GitService.deletedOrMissingSha
);
}
const diffArgs: DiffWithCommandArgs = {

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

@ -759,11 +759,15 @@ export class Git {
static async ls_files(
repoPath: string,
fileName: string,
options: { ref?: string } = {}
{ ref, untracked }: { ref?: string; untracked?: boolean } = {}
): Promise<string | undefined> {
const params = ['ls-files'];
if (options.ref && !Git.isUncommitted(options.ref)) {
params.push(`--with-tree=${options.ref}`);
if (ref && !Git.isUncommitted(ref)) {
params.push(`--with-tree=${ref}`);
}
if (!ref && untracked) {
params.push('-o');
}
const data = await git<string>({ cwd: repoPath, errors: GitErrorHandling.Ignore }, ...params, '--', fileName);

+ 24
- 5
src/git/gitService.ts View File

@ -1744,6 +1744,15 @@ export class GitService implements Disposable {
previous: await this.getPreviousUri(repoPath, uri, ref, skip - 1)
};
}
else if (status.workingTreeStatus !== undefined) {
return {
current: GitUri.fromFile(fileName, repoPath, undefined),
previous: await this.getPreviousUri(repoPath, uri, undefined, skip)
};
}
}
else if (skip === 0) {
skip++;
}
}
// If we are at the index (staged), diff staged with HEAD
@ -1934,7 +1943,7 @@ export class GitService implements Disposable {
Logger.error(ex, cc);
throw ex;
}
if (data == null || data.length === 0) throw new Error('File has no history');
if (data == null || data.length === 0) return undefined;
const [previousRef, file] = GitLogParser.parseSimple(data, skip, editorLine !== undefined ? ref : undefined);
// If the previous ref matches the ref we asked for assume we are at the end of the history
@ -2262,8 +2271,13 @@ export class GitService implements Disposable {
): Promise<Uri | undefined> {
if (ref === GitService.deletedOrMissingSha) return undefined;
if (!ref || (Git.isUncommitted(ref) && !Git.isUncommittedStaged(ref))) {
const data = await Git.ls_files(repoPath!, fileName);
if (ref == null || ref.length === 0 || (Git.isUncommitted(ref) && !Git.isUncommittedStaged(ref))) {
// Make sure the file exists in the repo
let data = await Git.ls_files(repoPath!, fileName);
if (data !== undefined) return GitUri.file(fileName);
// Check if the file exists untracked
data = await Git.ls_files(repoPath!, fileName, { untracked: true });
if (data !== undefined) return GitUri.file(fileName);
return undefined;
@ -2455,8 +2469,13 @@ export class GitService implements Disposable {
@log()
async resolveReference(repoPath: string, ref: string, uri?: Uri) {
const resolved = Git.isSha(ref) || !Git.isShaLike(ref) || ref.endsWith('^3');
if (uri == null) return resolved ? ref : (await Git.rev_parse(repoPath, ref)) || ref;
if (ref == null || ref.length === 0 || ref === GitService.deletedOrMissingSha) return ref;
if (uri == null) {
if (Git.isSha(ref) || !Git.isShaLike(ref) || ref.endsWith('^3')) return ref;
return (await Git.rev_parse(repoPath, ref)) || ref;
}
const ensuredRef = await Git.cat_file__resolve(
repoPath,

+ 9
- 7
src/git/gitUri.ts View File

@ -240,11 +240,13 @@ export class GitUri extends ((Uri as any) as UriEx) {
: (original && fileOrName.originalFileName) || fileOrName.fileName,
repoPath
);
return ref === undefined ? new GitUri(uri, repoPath) : new GitUri(uri, { repoPath: repoPath, sha: ref });
return ref == null || ref.length === 0
? new GitUri(uri, repoPath)
: new GitUri(uri, { repoPath: repoPath, sha: ref });
}
static fromRepoPath(repoPath: string, ref?: string) {
return ref === undefined
return ref == null || ref.length === 0
? new GitUri(GitUri.file(repoPath), repoPath)
: new GitUri(GitUri.file(repoPath), { repoPath: repoPath, sha: ref });
}
@ -403,14 +405,14 @@ export class GitUri extends ((Uri as any) as UriEx) {
shortSha = uriOrRef.shortSha;
}
if (ref === undefined || GitService.isUncommitted(ref)) {
if (GitService.isUncommittedStaged(ref)) {
return GitUri.git(fileName, repoPath);
}
if (ref == null || ref.length === 0) {
return Uri.file(fileName);
}
if (GitService.isUncommitted(ref)) {
return GitService.isUncommittedStaged(ref) ? GitUri.git(fileName, repoPath) : Uri.file(fileName);
}
const filePath = Strings.normalizePath(fileName, { addLeadingSlash: true });
const data: UriRevisionData = {
path: filePath,

+ 1
- 1
src/quickpicks/commitQuickPick.ts View File

@ -127,7 +127,7 @@ export class CommitQuickPick {
previousCommand = async () => {
const previousRef =
commit.previousSha === undefined || GitService.isShaParent(commit.previousSha)
? await Container.git.resolveReference(commit.repoPath, commit.previousSha || `${commit.sha}`)
? await Container.git.resolveReference(commit.repoPath, commit.previousSha || commit.sha)
: commit.previousSha;
if (previousRef === undefined) return KeyNoopCommand;

+ 40
- 19
src/views/nodes/statusFileNode.ts View File

@ -10,28 +10,49 @@ import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
import { ResourceType, ViewNode } from './viewNode';
export class StatusFileNode extends ViewNode {
private readonly _hasStagedChanges: boolean = false;
private readonly _hasUnstagedChanges: boolean = false;
constructor(
view: View,
parent: ViewNode,
public readonly repoPath: string,
public readonly file: GitFile,
public readonly commits: GitLogCommit[]
) {
super(GitUri.fromFile(file, repoPath, 'HEAD'), view, parent);
for (const c of this.commits) {
if (c.isUncommittedStaged) {
this._hasStagedChanges = true;
public readonly commits: GitLogCommit[];
public readonly file: GitFile;
public readonly repoPath: string;
private readonly _hasStagedChanges: boolean;
private readonly _hasUnstagedChanges: boolean;
constructor(view: View, parent: ViewNode, repoPath: string, file: GitFile, commits: GitLogCommit[]) {
let hasStagedChanges = false;
let hasUnstagedChanges = false;
let ref = undefined;
for (const c of commits) {
if (c.isUncommitted) {
if (c.isUncommittedStaged) {
hasStagedChanges = true;
if (!hasUnstagedChanges) {
ref = c.sha;
}
break;
}
else {
ref = undefined;
hasUnstagedChanges = true;
}
}
else if (c.isUncommitted) {
this._hasUnstagedChanges = true;
else if (hasUnstagedChanges || hasStagedChanges) {
break;
}
else {
ref = c.sha;
break;
}
if (this._hasStagedChanges && this._hasUnstagedChanges) break;
}
super(GitUri.fromFile(file, repoPath, ref), view, parent);
this.repoPath = repoPath;
this.file = file;
this.commits = commits;
this._hasStagedChanges = hasStagedChanges;
this._hasUnstagedChanges = hasUnstagedChanges;
}
getChildren(): ViewNode[] {

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

@ -345,8 +345,8 @@ export class ViewCommands implements Disposable {
void commands.executeCommand(BuiltInCommands.FocusFilesExplorer);
}
private openChanges(node: ViewRefFileNode) {
if (!(node instanceof ViewRefFileNode)) return undefined;
private openChanges(node: ViewRefFileNode | StatusFileNode) {
if (!(node instanceof ViewRefFileNode) && !(node instanceof StatusFileNode)) return undefined;
const command = node.getCommand();
if (command === undefined || command.arguments === undefined) return undefined;
@ -356,8 +356,8 @@ export class ViewCommands implements Disposable {
return commands.executeCommand(command.command, uri, args);
}
private async openChangesWithWorking(node: ViewRefFileNode) {
if (!(node instanceof ViewRefFileNode)) return undefined;
private async openChangesWithWorking(node: ViewRefFileNode | StatusFileNode) {
if (!(node instanceof ViewRefFileNode) && !(node instanceof StatusFileNode)) return undefined;
const args: DiffWithWorkingCommandArgs = {
showOptions: {

Loading…
Cancel
Save