Skip to content

Commit 07ec5e6

Browse files
committed
Fixes #740 - opening untracked status files fails
Fixes diff w/ previous when there are no working file changes Fixes broken status file commands
1 parent 8c6690d commit 07ec5e6

File tree

9 files changed

+113
-43
lines changed

9 files changed

+113
-43
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
66

7+
## [Unreleased]
8+
9+
## Fixed
10+
11+
- Fixes [#740](https://github.com/eamodio/vscode-gitlens/issues/740) - Opening untracked files from "files changed" section fails
12+
- 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)
13+
- 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
14+
715
## [9.7.2] - 2019-05-10
816

917
## Fixed

src/commands/diffWith.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export class DiffWithCommand extends ActiveEditorCommand {
136136
let lhsSuffix = args.lhs.sha !== GitService.deletedOrMissingSha ? GitService.shortenSha(lhsSha) || '' : '';
137137
if (lhs === undefined && args.rhs.sha.length === 0) {
138138
if (rhs !== undefined) {
139-
lhsSuffix = `not in ${lhsSuffix}`;
139+
lhsSuffix = lhsSuffix.length === 0 ? '' : `not in ${lhsSuffix}`;
140140
rhsSuffix = '';
141141
}
142142
else {

src/commands/diffWithPrevious.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
'use strict';
22
import { commands, TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
33
import { Container } from '../container';
4-
import { GitCommit, GitUri } from '../git/gitService';
4+
import { GitCommit, GitService, GitUri } from '../git/gitService';
55
import { Logger } from '../logger';
66
import { Messages } from '../messages';
7-
import { ActiveEditorCommand, command, CommandContext, Commands, getCommandUri } from './common';
7+
import { ActiveEditorCommand, command, CommandContext, Commands, getCommandUri, openEditor } from './common';
88
import { DiffWithCommandArgs } from './diffWith';
99
import { UriComparer } from '../comparers';
1010

@@ -61,7 +61,23 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
6161
);
6262

6363
if (diffUris === undefined || diffUris.previous === undefined) {
64-
return Messages.showCommitHasNoPreviousCommitWarningMessage();
64+
if (diffUris === undefined) return Messages.showCommitHasNoPreviousCommitWarningMessage();
65+
66+
// If we have no previous and the current is the working file, just open the working file
67+
if (diffUris.current.sha === undefined) {
68+
return openEditor(diffUris.current, args.showOptions);
69+
}
70+
71+
if (!diffUris.current.isUncommittedStaged) {
72+
return Messages.showCommitHasNoPreviousCommitWarningMessage();
73+
}
74+
75+
// If we have no previous and the current is staged, then diff staged with missing
76+
diffUris.previous = GitUri.fromFile(
77+
diffUris.current.fileName,
78+
diffUris.current.repoPath!,
79+
GitService.deletedOrMissingSha
80+
);
6581
}
6682

6783
const diffArgs: DiffWithCommandArgs = {

src/git/git.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,11 +759,15 @@ export class Git {
759759
static async ls_files(
760760
repoPath: string,
761761
fileName: string,
762-
options: { ref?: string } = {}
762+
{ ref, untracked }: { ref?: string; untracked?: boolean } = {}
763763
): Promise<string | undefined> {
764764
const params = ['ls-files'];
765-
if (options.ref && !Git.isUncommitted(options.ref)) {
766-
params.push(`--with-tree=${options.ref}`);
765+
if (ref && !Git.isUncommitted(ref)) {
766+
params.push(`--with-tree=${ref}`);
767+
}
768+
769+
if (!ref && untracked) {
770+
params.push('-o');
767771
}
768772

769773
const data = await git<string>({ cwd: repoPath, errors: GitErrorHandling.Ignore }, ...params, '--', fileName);

src/git/gitService.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,15 @@ export class GitService implements Disposable {
17441744
previous: await this.getPreviousUri(repoPath, uri, ref, skip - 1)
17451745
};
17461746
}
1747+
else if (status.workingTreeStatus !== undefined) {
1748+
return {
1749+
current: GitUri.fromFile(fileName, repoPath, undefined),
1750+
previous: await this.getPreviousUri(repoPath, uri, undefined, skip)
1751+
};
1752+
}
1753+
}
1754+
else if (skip === 0) {
1755+
skip++;
17471756
}
17481757
}
17491758
// If we are at the index (staged), diff staged with HEAD
@@ -1934,7 +1943,7 @@ export class GitService implements Disposable {
19341943
Logger.error(ex, cc);
19351944
throw ex;
19361945
}
1937-
if (data == null || data.length === 0) throw new Error('File has no history');
1946+
if (data == null || data.length === 0) return undefined;
19381947

19391948
const [previousRef, file] = GitLogParser.parseSimple(data, skip, editorLine !== undefined ? ref : undefined);
19401949
// 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 {
22622271
): Promise<Uri | undefined> {
22632272
if (ref === GitService.deletedOrMissingSha) return undefined;
22642273

2265-
if (!ref || (Git.isUncommitted(ref) && !Git.isUncommittedStaged(ref))) {
2266-
const data = await Git.ls_files(repoPath!, fileName);
2274+
if (ref == null || ref.length === 0 || (Git.isUncommitted(ref) && !Git.isUncommittedStaged(ref))) {
2275+
// Make sure the file exists in the repo
2276+
let data = await Git.ls_files(repoPath!, fileName);
2277+
if (data !== undefined) return GitUri.file(fileName);
2278+
2279+
// Check if the file exists untracked
2280+
data = await Git.ls_files(repoPath!, fileName, { untracked: true });
22672281
if (data !== undefined) return GitUri.file(fileName);
22682282

22692283
return undefined;
@@ -2455,8 +2469,13 @@ export class GitService implements Disposable {
24552469

24562470
@log()
24572471
async resolveReference(repoPath: string, ref: string, uri?: Uri) {
2458-
const resolved = Git.isSha(ref) || !Git.isShaLike(ref) || ref.endsWith('^3');
2459-
if (uri == null) return resolved ? ref : (await Git.rev_parse(repoPath, ref)) || ref;
2472+
if (ref == null || ref.length === 0 || ref === GitService.deletedOrMissingSha) return ref;
2473+
2474+
if (uri == null) {
2475+
if (Git.isSha(ref) || !Git.isShaLike(ref) || ref.endsWith('^3')) return ref;
2476+
2477+
return (await Git.rev_parse(repoPath, ref)) || ref;
2478+
}
24602479

24612480
const ensuredRef = await Git.cat_file__resolve(
24622481
repoPath,

src/git/gitUri.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,13 @@ export class GitUri extends ((Uri as any) as UriEx) {
240240
: (original && fileOrName.originalFileName) || fileOrName.fileName,
241241
repoPath
242242
);
243-
return ref === undefined ? new GitUri(uri, repoPath) : new GitUri(uri, { repoPath: repoPath, sha: ref });
243+
return ref == null || ref.length === 0
244+
? new GitUri(uri, repoPath)
245+
: new GitUri(uri, { repoPath: repoPath, sha: ref });
244246
}
245247

246248
static fromRepoPath(repoPath: string, ref?: string) {
247-
return ref === undefined
249+
return ref == null || ref.length === 0
248250
? new GitUri(GitUri.file(repoPath), repoPath)
249251
: new GitUri(GitUri.file(repoPath), { repoPath: repoPath, sha: ref });
250252
}
@@ -403,14 +405,14 @@ export class GitUri extends ((Uri as any) as UriEx) {
403405
shortSha = uriOrRef.shortSha;
404406
}
405407

406-
if (ref === undefined || GitService.isUncommitted(ref)) {
407-
if (GitService.isUncommittedStaged(ref)) {
408-
return GitUri.git(fileName, repoPath);
409-
}
410-
408+
if (ref == null || ref.length === 0) {
411409
return Uri.file(fileName);
412410
}
413411

412+
if (GitService.isUncommitted(ref)) {
413+
return GitService.isUncommittedStaged(ref) ? GitUri.git(fileName, repoPath) : Uri.file(fileName);
414+
}
415+
414416
const filePath = Strings.normalizePath(fileName, { addLeadingSlash: true });
415417
const data: UriRevisionData = {
416418
path: filePath,

src/quickpicks/commitQuickPick.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class CommitQuickPick {
127127
previousCommand = async () => {
128128
const previousRef =
129129
commit.previousSha === undefined || GitService.isShaParent(commit.previousSha)
130-
? await Container.git.resolveReference(commit.repoPath, commit.previousSha || `${commit.sha}`)
130+
? await Container.git.resolveReference(commit.repoPath, commit.previousSha || commit.sha)
131131
: commit.previousSha;
132132
if (previousRef === undefined) return KeyNoopCommand;
133133

src/views/nodes/statusFileNode.ts

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,49 @@ import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
1010
import { ResourceType, ViewNode } from './viewNode';
1111

1212
export class StatusFileNode extends ViewNode {
13-
private readonly _hasStagedChanges: boolean = false;
14-
private readonly _hasUnstagedChanges: boolean = false;
15-
16-
constructor(
17-
view: View,
18-
parent: ViewNode,
19-
public readonly repoPath: string,
20-
public readonly file: GitFile,
21-
public readonly commits: GitLogCommit[]
22-
) {
23-
super(GitUri.fromFile(file, repoPath, 'HEAD'), view, parent);
24-
25-
for (const c of this.commits) {
26-
if (c.isUncommittedStaged) {
27-
this._hasStagedChanges = true;
13+
public readonly commits: GitLogCommit[];
14+
public readonly file: GitFile;
15+
public readonly repoPath: string;
16+
17+
private readonly _hasStagedChanges: boolean;
18+
private readonly _hasUnstagedChanges: boolean;
19+
20+
constructor(view: View, parent: ViewNode, repoPath: string, file: GitFile, commits: GitLogCommit[]) {
21+
let hasStagedChanges = false;
22+
let hasUnstagedChanges = false;
23+
let ref = undefined;
24+
for (const c of commits) {
25+
if (c.isUncommitted) {
26+
if (c.isUncommittedStaged) {
27+
hasStagedChanges = true;
28+
if (!hasUnstagedChanges) {
29+
ref = c.sha;
30+
}
31+
32+
break;
33+
}
34+
else {
35+
ref = undefined;
36+
hasUnstagedChanges = true;
37+
}
2838
}
29-
else if (c.isUncommitted) {
30-
this._hasUnstagedChanges = true;
39+
else if (hasUnstagedChanges || hasStagedChanges) {
40+
break;
41+
}
42+
else {
43+
ref = c.sha;
44+
break;
3145
}
32-
33-
if (this._hasStagedChanges && this._hasUnstagedChanges) break;
3446
}
47+
48+
super(GitUri.fromFile(file, repoPath, ref), view, parent);
49+
50+
this.repoPath = repoPath;
51+
this.file = file;
52+
this.commits = commits;
53+
54+
this._hasStagedChanges = hasStagedChanges;
55+
this._hasUnstagedChanges = hasUnstagedChanges;
3556
}
3657

3758
getChildren(): ViewNode[] {

src/views/viewCommands.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,8 @@ export class ViewCommands implements Disposable {
345345
void commands.executeCommand(BuiltInCommands.FocusFilesExplorer);
346346
}
347347

348-
private openChanges(node: ViewRefFileNode) {
349-
if (!(node instanceof ViewRefFileNode)) return undefined;
348+
private openChanges(node: ViewRefFileNode | StatusFileNode) {
349+
if (!(node instanceof ViewRefFileNode) && !(node instanceof StatusFileNode)) return undefined;
350350

351351
const command = node.getCommand();
352352
if (command === undefined || command.arguments === undefined) return undefined;
@@ -356,8 +356,8 @@ export class ViewCommands implements Disposable {
356356
return commands.executeCommand(command.command, uri, args);
357357
}
358358

359-
private async openChangesWithWorking(node: ViewRefFileNode) {
360-
if (!(node instanceof ViewRefFileNode)) return undefined;
359+
private async openChangesWithWorking(node: ViewRefFileNode | StatusFileNode) {
360+
if (!(node instanceof ViewRefFileNode) && !(node instanceof StatusFileNode)) return undefined;
361361

362362
const args: DiffWithWorkingCommandArgs = {
363363
showOptions: {

0 commit comments

Comments
 (0)