Просмотр исходного кода

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 лет назад
Родитель
Сommit
07ec5e68e6
9 измененных файлов: 113 добавлений и 43 удалений
  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 Просмотреть файл

@ -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/). 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 ## [9.7.2] - 2019-05-10
## Fixed ## Fixed

+ 1
- 1
src/commands/diffWith.ts Просмотреть файл

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

+ 19
- 3
src/commands/diffWithPrevious.ts Просмотреть файл

@ -1,10 +1,10 @@
'use strict'; 'use strict';
import { commands, TextDocumentShowOptions, TextEditor, Uri } from 'vscode'; import { commands, TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { Container } from '../container'; import { Container } from '../container';
import { GitCommit, GitUri } from '../git/gitService';
import { GitCommit, GitService, GitUri } from '../git/gitService';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { Messages } from '../messages'; 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 { DiffWithCommandArgs } from './diffWith';
import { UriComparer } from '../comparers'; import { UriComparer } from '../comparers';
@ -61,7 +61,23 @@ export class DiffWithPreviousCommand extends ActiveEditorCommand {
); );
if (diffUris === undefined || diffUris.previous === undefined) { 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 = { const diffArgs: DiffWithCommandArgs = {

+ 7
- 3
src/git/git.ts Просмотреть файл

@ -759,11 +759,15 @@ export class Git {
static async ls_files( static async ls_files(
repoPath: string, repoPath: string,
fileName: string, fileName: string,
options: { ref?: string } = {}
{ ref, untracked }: { ref?: string; untracked?: boolean } = {}
): Promise<string | undefined> { ): Promise<string | undefined> {
const params = ['ls-files']; 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); const data = await git<string>({ cwd: repoPath, errors: GitErrorHandling.Ignore }, ...params, '--', fileName);

+ 24
- 5
src/git/gitService.ts Просмотреть файл

@ -1744,6 +1744,15 @@ export class GitService implements Disposable {
previous: await this.getPreviousUri(repoPath, uri, ref, skip - 1) 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 // If we are at the index (staged), diff staged with HEAD
@ -1934,7 +1943,7 @@ export class GitService implements Disposable {
Logger.error(ex, cc); Logger.error(ex, cc);
throw ex; 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); 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 // 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> { ): Promise<Uri | undefined> {
if (ref === GitService.deletedOrMissingSha) return 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); if (data !== undefined) return GitUri.file(fileName);
return undefined; return undefined;
@ -2455,8 +2469,13 @@ export class GitService implements Disposable {
@log() @log()
async resolveReference(repoPath: string, ref: string, uri?: Uri) { 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( const ensuredRef = await Git.cat_file__resolve(
repoPath, repoPath,

+ 9
- 7
src/git/gitUri.ts Просмотреть файл

@ -240,11 +240,13 @@ export class GitUri extends ((Uri as any) as UriEx) {
: (original && fileOrName.originalFileName) || fileOrName.fileName, : (original && fileOrName.originalFileName) || fileOrName.fileName,
repoPath 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) { 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)
: new GitUri(GitUri.file(repoPath), { repoPath: repoPath, sha: ref }); : 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; 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); 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 filePath = Strings.normalizePath(fileName, { addLeadingSlash: true });
const data: UriRevisionData = { const data: UriRevisionData = {
path: filePath, path: filePath,

+ 1
- 1
src/quickpicks/commitQuickPick.ts Просмотреть файл

@ -127,7 +127,7 @@ export class CommitQuickPick {
previousCommand = async () => { previousCommand = async () => {
const previousRef = const previousRef =
commit.previousSha === undefined || GitService.isShaParent(commit.previousSha) 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; : commit.previousSha;
if (previousRef === undefined) return KeyNoopCommand; if (previousRef === undefined) return KeyNoopCommand;

+ 40
- 19
src/views/nodes/statusFileNode.ts Просмотреть файл

@ -10,28 +10,49 @@ import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode';
import { ResourceType, ViewNode } from './viewNode'; import { ResourceType, ViewNode } from './viewNode';
export class StatusFileNode extends 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[] { getChildren(): ViewNode[] {

+ 4
- 4
src/views/viewCommands.ts Просмотреть файл

@ -345,8 +345,8 @@ export class ViewCommands implements Disposable {
void commands.executeCommand(BuiltInCommands.FocusFilesExplorer); 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(); const command = node.getCommand();
if (command === undefined || command.arguments === undefined) return undefined; if (command === undefined || command.arguments === undefined) return undefined;
@ -356,8 +356,8 @@ export class ViewCommands implements Disposable {
return commands.executeCommand(command.command, uri, args); 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 = { const args: DiffWithWorkingCommandArgs = {
showOptions: { showOptions: {

Загрузка…
Отмена
Сохранить