Browse Source

Adds merge status (wip)

main
Eric Amodio 4 years ago
parent
commit
4e908cb758
12 changed files with 542 additions and 47 deletions
  1. +11
    -4
      src/git/git.ts
  2. +34
    -4
      src/git/gitService.ts
  3. +10
    -0
      src/git/models/merge.ts
  4. +1
    -0
      src/git/models/models.ts
  5. +1
    -0
      src/views/branchesView.ts
  6. +1
    -0
      src/views/nodes.ts
  7. +48
    -26
      src/views/nodes/branchNode.ts
  8. +45
    -4
      src/views/nodes/fileRevisionAsCommitNode.ts
  9. +311
    -0
      src/views/nodes/mergeStatusNode.ts
  10. +7
    -1
      src/views/nodes/repositoryNode.ts
  11. +3
    -0
      src/views/nodes/viewNode.ts
  12. +70
    -8
      src/views/viewCommands.ts

+ 11
- 4
src/git/git.ts View File

@ -376,21 +376,28 @@ export namespace Git {
);
}
export function branch__contains(
export function branch__containsOrPointsAt(
repoPath: string,
ref: string,
{ name = undefined, remotes = false }: { name?: string; remotes?: boolean } = {},
{
mode = 'contains',
name = undefined,
remotes = false,
}: { mode?: 'contains' | 'pointsAt'; name?: string; remotes?: boolean } = {},
) {
const params = ['branch'];
if (remotes) {
params.push('-r');
}
params.push('--contains', ref);
params.push(mode === 'pointsAt' ? `--points-at=${ref}` : `--contains=${ref}`, '--format=%(refname:short)');
if (name != null) {
params.push(name);
}
return git<string>({ cwd: repoPath, configs: ['-c', 'color.branch=false'] }, ...params);
return git<string>(
{ cwd: repoPath, configs: ['-c', 'color.branch=false'], errors: GitErrorHandling.Ignore },
...params,
);
}
export function check_ignore(repoPath: string, ...files: string[]) {

+ 34
- 4
src/git/gitService.ts View File

@ -50,6 +50,7 @@ import {
GitLog,
GitLogCommit,
GitLogParser,
GitMergeStatus,
GitReference,
GitReflog,
GitRemote,
@ -580,7 +581,7 @@ export class GitService implements Disposable {
@log()
async branchContainsCommit(repoPath: string, name: string, ref: string): Promise<boolean> {
let data = await Git.branch__contains(repoPath, ref, { name: name });
let data = await Git.branch__containsOrPointsAt(repoPath, ref, { mode: 'contains', name: name });
data = data?.trim();
return Boolean(data);
}
@ -1348,13 +1349,17 @@ export class GitService implements Disposable {
}
@log()
async getCommitBranches(repoPath: string, ref: string, options?: { remotes?: boolean }): Promise<string[]> {
const data = await Git.branch__contains(repoPath, ref, options);
async getCommitBranches(
repoPath: string,
ref: string,
options?: { mode?: 'contains' | 'pointsAt'; remotes?: boolean },
): Promise<string[]> {
const data = await Git.branch__containsOrPointsAt(repoPath, ref, options);
if (!data) return [];
return data
.split('\n')
.map(b => b.substr(2).trim())
.map(b => b.trim())
.filter(<T>(i?: T): i is T => Boolean(i));
}
@ -2374,6 +2379,31 @@ export class GitService implements Disposable {
}
}
async getMergeStatus(repoPath: string): Promise<GitMergeStatus | undefined>;
async getMergeStatus(status: GitStatus): Promise<GitMergeStatus | undefined>;
@log({ args: false })
async getMergeStatus(repoPathOrStatus: string | GitStatus): Promise<GitMergeStatus | undefined> {
let status;
if (typeof repoPathOrStatus === 'string') {
status = await this.getStatusForRepo(repoPathOrStatus);
} else {
status = repoPathOrStatus;
}
if (status?.hasConflicts !== true) return undefined;
const [mergeBase, possibleSourceBranches] = await Promise.all([
Container.git.getMergeBase(status.repoPath, 'MERGE_HEAD', 'HEAD'),
Container.git.getCommitBranches(status.repoPath, 'MERGE_HEAD', { mode: 'pointsAt' }),
]);
return {
repoPath: status.repoPath,
mergeBase: mergeBase,
conflicts: status.files.filter(f => f.conflicted),
into: status.branch,
incoming: possibleSourceBranches?.length === 1 ? possibleSourceBranches[0] : undefined,
};
}
@log()
async getNextDiffUris(
repoPath: string,

+ 10
- 0
src/git/models/merge.ts View File

@ -0,0 +1,10 @@
'use strict';
import { GitStatusFile } from './status';
export interface GitMergeStatus {
repoPath: string;
into: string;
mergeBase: string | undefined;
incoming: string | undefined;
conflicts: GitStatusFile[];
}

+ 1
- 0
src/git/models/models.ts View File

@ -349,6 +349,7 @@ export * from './file';
export * from './issue';
export * from './log';
export * from './logCommit';
export * from './merge';
export * from './pullRequest';
export * from './reflog';
export * from './remote';

+ 1
- 0
src/views/branchesView.ts View File

@ -49,6 +49,7 @@ export class BranchesRepositoryNode extends RepositoryFolderNode
protected changed(e: RepositoryChangeEvent) {
return (
e.changed(RepositoryChange.Config) ||
e.changed(RepositoryChange.Index) ||
e.changed(RepositoryChange.Heads) ||
e.changed(RepositoryChange.Remotes) ||
e.changed(RepositoryChange.Unknown)

+ 1
- 0
src/views/nodes.ts View File

@ -21,6 +21,7 @@ export * from './nodes/fileRevisionAsCommitNode';
export * from './nodes/folderNode';
export * from './nodes/lineHistoryNode';
export * from './nodes/lineHistoryTrackerNode';
export * from './nodes/mergeStatusNode';
export * from './nodes/pullRequestNode';
export * from './nodes/reflogNode';
export * from './nodes/reflogRecordNode';

+ 48
- 26
src/views/nodes/branchNode.ts View File

@ -20,6 +20,7 @@ import {
} from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { insertDateMarkers } from './helpers';
import { MergeStatusNode } from './mergeStatusNode';
import { PullRequestNode } from './pullRequestNode';
import { RemotesView } from '../remotesView';
import { RepositoriesView } from '../repositoriesView';
@ -120,9 +121,12 @@ export class BranchNode
const children = [];
const range = await Container.git.getBranchAheadRange(this.branch);
const [log, getBranchAndTagTips, pr, unpublishedCommits] = await Promise.all([
const [log, getBranchAndTagTips, mergeStatus, pr, unpublishedCommits] = await Promise.all([
this.getLog(),
Container.git.getBranchesAndTagsTipsFn(this.uri.repoPath, this.branch.name),
this.options.showTracking && this.branch.current
? Container.git.getMergeStatus(this.uri.repoPath!)
: undefined,
this.view.config.pullRequests.enabled &&
this.view.config.pullRequests.showForBranches &&
(this.branch.tracking || this.branch.remote)
@ -155,35 +159,53 @@ export class BranchNode
}
if (this.options.showTracking) {
const status = {
ref: this.branch.ref,
repoPath: this.branch.repoPath,
state: this.branch.state,
upstream: this.branch.tracking,
};
if (this.branch.tracking) {
if (this.root && !status.state.behind && !status.state.ahead) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'same', this.root),
);
} else {
if (status.state.behind) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'behind', this.root),
);
}
if (status.state.ahead) {
if (mergeStatus != null) {
children.push(new MergeStatusNode(this.view, this, this.branch, mergeStatus));
} else {
const status = {
ref: this.branch.ref,
repoPath: this.branch.repoPath,
state: this.branch.state,
upstream: this.branch.tracking,
};
if (this.branch.tracking) {
if (this.root && !status.state.behind && !status.state.ahead) {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'ahead', this.root),
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'same', this.root),
);
} else {
if (status.state.behind) {
children.push(
new BranchTrackingStatusNode(
this.view,
this,
this.branch,
status,
'behind',
this.root,
),
);
}
if (status.state.ahead) {
children.push(
new BranchTrackingStatusNode(
this.view,
this,
this.branch,
status,
'ahead',
this.root,
),
);
}
}
} else {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'none', this.root),
);
}
} else {
children.push(
new BranchTrackingStatusNode(this.view, this, this.branch, status, 'none', this.root),
);
}
}

+ 45
- 4
src/views/nodes/fileRevisionAsCommitNode.ts View File

@ -1,6 +1,6 @@
'use strict';
import * as paths from 'path';
import { Command, Selection, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Command, Selection, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { Commands, DiffWithPreviousCommandArgs } from '../../commands';
import { GlyphChars } from '../../constants';
import { Container } from '../../container';
@ -15,6 +15,7 @@ import {
} from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { LineHistoryView } from '../lineHistoryView';
import { MergeConflictCurrentChangesNode, MergeConflictIncomingChangesNode } from './mergeStatusNode';
import { ViewsWithCommits } from '../viewBase';
import { ContextValues, ViewNode, ViewRefFileNode } from './viewNode';
@ -51,8 +52,16 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode
return this.commit;
}
getChildren(): ViewNode[] {
return [];
async getChildren(): Promise<ViewNode[]> {
if (!this.commit.hasConflicts) return [];
const mergeStatus = await Container.git.getMergeStatus(this.commit.repoPath);
if (mergeStatus == null) return [];
return [
new MergeConflictCurrentChangesNode(this.view, this, mergeStatus, this.file),
new MergeConflictIncomingChangesNode(this.view, this, mergeStatus, this.file),
];
}
async getTreeItem(): Promise<TreeItem> {
@ -77,7 +86,7 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode
dateFormat: Container.config.defaultDateFormat,
messageTruncateAtNewLine: true,
}),
TreeItemCollapsibleState.None,
this.commit.hasConflicts ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None,
);
item.contextValue = this.contextValue;
@ -148,6 +157,31 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode
line = this._options.selection !== undefined ? this._options.selection.active.line : 0;
}
if (this.commit.hasConflicts) {
return {
title: 'Open Changes',
command: Commands.DiffWith,
arguments: [
{
lhs: {
sha: 'MERGE_HEAD',
uri: GitUri.fromFile(this.file, this.repoPath, undefined, true),
},
rhs: {
sha: 'HEAD',
uri: GitUri.fromFile(this.file, this.repoPath),
},
repoPath: this.repoPath,
line: 0,
showOptions: {
preserveFocus: false,
preview: false,
},
},
],
};
}
const commandArgs: DiffWithPreviousCommandArgs = {
commit: this.commit,
uri: GitUri.fromFile(this.file, this.commit.repoPath),
@ -163,4 +197,11 @@ export class FileRevisionAsCommitNode extends ViewRefFileNode
arguments: [undefined, commandArgs],
};
}
async getConflictBaseUri(): Promise<Uri | undefined> {
if (!this.commit.hasConflicts) return undefined;
const mergeBase = await Container.git.getMergeBase(this.repoPath, 'MERGE_HEAD', 'HEAD');
return GitUri.fromFile(this.file, this.repoPath, mergeBase ?? 'HEAD');
}
}

+ 311
- 0
src/views/nodes/mergeStatusNode.ts View File

@ -0,0 +1,311 @@
'use strict';
import * as paths from 'path';
import { Command, MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
import { BranchNode } from './branchNode';
import { Commands, DiffWithCommandArgs } from '../../commands';
import { ViewFilesLayout } from '../../configuration';
import { BuiltInCommands } from '../../constants';
import { FileNode, FolderNode } from './folderNode';
import { GitBranch, GitFile, GitMergeStatus, StatusFileFormatter } from '../../git/git';
import { GitUri } from '../../git/gitUri';
import { Arrays, Strings } from '../../system';
import { View, ViewsWithCommits } from '../viewBase';
import { ContextValues, ViewNode } from './viewNode';
export class MergeStatusNode extends ViewNode<ViewsWithCommits> {
static key = ':merge';
static getId(repoPath: string, name: string): string {
return `${BranchNode.getId(repoPath, name, true)}${this.key}`;
}
constructor(
view: ViewsWithCommits,
parent: ViewNode,
public readonly branch: GitBranch,
public readonly status: GitMergeStatus,
) {
super(GitUri.fromRepoPath(status.repoPath), view, parent);
}
get id(): string {
return MergeStatusNode.getId(this.status.repoPath, this.status.into);
}
get repoPath(): string {
return this.uri.repoPath!;
}
getChildren(): ViewNode[] {
let children: FileNode[] = this.status.conflicts.map(
f => new MergeConflictFileNode(this.view, this, this.status, f),
);
if (this.view.config.files.layout !== ViewFilesLayout.List) {
const hierarchy = Arrays.makeHierarchical(
children,
n => n.uri.relativePath.split('/'),
(...parts: string[]) => Strings.normalizePath(paths.join(...parts)),
this.view.config.files.compact,
);
const root = new FolderNode(this.view, this, this.repoPath, '', hierarchy);
children = root.getChildren() as FileNode[];
} else {
children.sort((a, b) =>
a.label!.localeCompare(b.label!, undefined, { numeric: true, sensitivity: 'base' }),
);
}
return children;
}
getTreeItem(): TreeItem {
const item = new TreeItem(
`Resolve conflicts before merging ${this.status.incoming ? `${this.status.incoming} ` : ''}into ${
this.status.into
}`,
TreeItemCollapsibleState.Expanded,
);
item.id = this.id;
item.contextValue = ContextValues.Merge;
item.description = Strings.pluralize('conflict', this.status.conflicts.length);
item.iconPath = new ThemeIcon('warning', new ThemeColor('list.warningForeground'));
item.tooltip = new MarkdownString(
`Merging ${this.status.incoming ? `$(git-branch) ${this.status.incoming} ` : ''} into $(git-branch) ${
this.status.into
}\n\n${Strings.pluralize('conflicted file', this.status.conflicts.length)}
`,
true,
);
return item;
}
}
export class MergeConflictFileNode extends ViewNode implements FileNode {
constructor(view: View, parent: ViewNode, private readonly status: GitMergeStatus, public readonly file: GitFile) {
super(GitUri.fromFile(file, status.repoPath, 'MERGE_HEAD'), view, parent);
}
toClipboard(): string {
return this.fileName;
}
get baseUri(): Uri {
return GitUri.fromFile(this.file, this.status.repoPath, this.status.mergeBase ?? 'HEAD');
}
get fileName(): string {
return this.file.fileName;
}
get repoPath(): string {
return this.status.repoPath;
}
getChildren(): ViewNode[] {
return [
new MergeConflictCurrentChangesNode(this.view, this, this.status, this.file),
new MergeConflictIncomingChangesNode(this.view, this, this.status, this.file),
];
}
getTreeItem(): TreeItem {
const item = new TreeItem(this.label, TreeItemCollapsibleState.Collapsed);
item.description = this.description;
item.contextValue = `${ContextValues.File}+conflicted`;
item.tooltip = StatusFileFormatter.fromTemplate(
// eslint-disable-next-line no-template-curly-in-string
'${file}\n${directory}/\n\n${status}${ (originalPath)} in Index (staged)',
this.file,
);
// Use the file icon and decorations
item.resourceUri = GitUri.resolveToUri(this.file.fileName, this.repoPath);
item.iconPath = ThemeIcon.File;
item.command = this.getCommand();
// Only cache the label/description for a single refresh
this._label = undefined;
this._description = undefined;
return item;
}
private _description: string | undefined;
get description() {
if (this._description == null) {
this._description = StatusFileFormatter.fromTemplate(
this.view.config.formats.files.description,
this.file,
{
relativePath: this.relativePath,
},
);
}
return this._description;
}
private _folderName: string | undefined;
get folderName() {
if (this._folderName == null) {
this._folderName = paths.dirname(this.uri.relativePath);
}
return this._folderName;
}
private _label: string | undefined;
get label() {
if (this._label == null) {
this._label = StatusFileFormatter.fromTemplate(this.view.config.formats.files.label, this.file, {
relativePath: this.relativePath,
});
}
return this._label;
}
get priority(): number {
return 0;
}
private _relativePath: string | undefined;
get relativePath(): string | undefined {
return this._relativePath;
}
set relativePath(value: string | undefined) {
this._relativePath = value;
this._label = undefined;
this._description = undefined;
}
getCommand(): Command | undefined {
return {
title: 'Open File',
command: BuiltInCommands.Open,
arguments: [
GitUri.resolveToUri(this.file.fileName, this.repoPath),
{
preserveFocus: true,
preview: true,
},
],
};
}
}
export class MergeConflictCurrentChangesNode extends ViewNode {
constructor(view: View, parent: ViewNode, private readonly status: GitMergeStatus, private readonly file: GitFile) {
super(GitUri.fromFile(file, status.repoPath, 'HEAD'), view, parent);
}
getChildren(): ViewNode[] {
return [];
}
getTreeItem(): TreeItem {
const item = new TreeItem('Current changes', TreeItemCollapsibleState.None);
item.contextValue = ContextValues.MergeCurrentChanges;
item.description = this.status.into;
item.iconPath = new ThemeIcon('diff');
item.tooltip = new MarkdownString(
`Current changes to $(file) ${this.file.fileName} on $(git-branch) ${this.status.into}`,
true,
);
item.command = this.getCommand();
return item;
}
getCommand(): Command | undefined {
if (this.status.mergeBase == null) {
return {
title: 'Open Revision',
command: BuiltInCommands.Open,
arguments: [GitUri.toRevisionUri('HEAD', this.file.fileName, this.status.repoPath)],
};
}
const commandArgs: DiffWithCommandArgs = {
lhs: {
sha: this.status.mergeBase,
uri: GitUri.fromFile(this.file, this.status.repoPath, undefined, true),
title: `${this.file.fileName} (merge-base)`,
},
rhs: {
sha: 'HEAD',
uri: GitUri.fromFile(this.file, this.status.repoPath),
title: `${this.file.fileName} (${this.status.into})`,
},
repoPath: this.status.repoPath,
line: 0,
showOptions: {
preserveFocus: true,
preview: true,
},
};
return {
title: 'Open Changes',
command: Commands.DiffWith,
arguments: [commandArgs],
};
}
}
export class MergeConflictIncomingChangesNode extends ViewNode {
constructor(view: View, parent: ViewNode, private readonly status: GitMergeStatus, private readonly file: GitFile) {
super(GitUri.fromFile(file, status.repoPath, 'MERGE_HEAD'), view, parent);
}
getChildren(): ViewNode[] {
return [];
}
getTreeItem(): TreeItem {
const item = new TreeItem('Incoming changes', TreeItemCollapsibleState.None);
item.contextValue = ContextValues.MergeIncomingChanges;
item.description = this.status.incoming;
item.iconPath = new ThemeIcon('diff');
item.tooltip = new MarkdownString(
`Incoming changes to $(file) ${this.file.fileName}${
this.status.incoming ? ` from $(git-branch) ${this.status.incoming}` : ''
}`,
true,
);
item.command = this.getCommand();
return item;
}
getCommand(): Command | undefined {
if (this.status.mergeBase == null) {
return {
title: 'Open Revision',
command: BuiltInCommands.Open,
arguments: [GitUri.toRevisionUri('MERGE_HEAD', this.file.fileName, this.status.repoPath)],
};
}
const commandArgs: DiffWithCommandArgs = {
lhs: {
sha: this.status.mergeBase,
uri: GitUri.fromFile(this.file, this.status.repoPath, undefined, true),
title: `${this.file.fileName} (merge-base)`,
},
rhs: {
sha: 'MERGE_HEAD',
uri: GitUri.fromFile(this.file, this.status.repoPath),
title: `${this.file.fileName} (${this.status.incoming ? this.status.incoming : 'incoming'})`,
},
repoPath: this.status.repoPath,
line: 0,
showOptions: {
preserveFocus: true,
preview: true,
},
};
return {
title: 'Open Changes',
command: Commands.DiffWith,
arguments: [commandArgs],
};
}
}

+ 7
- 1
src/views/nodes/repositoryNode.ts View File

@ -20,6 +20,7 @@ import { BranchNode } from './branchNode';
import { BranchTrackingStatusNode } from './branchTrackingStatusNode';
import { MessageNode } from './common';
import { ContributorsNode } from './contributorsNode';
import { MergeStatusNode } from './mergeStatusNode';
import { ReflogNode } from './reflogNode';
import { RemotesNode } from './remotesNode';
import { StashesNode } from './stashesNode';
@ -82,7 +83,12 @@ export class RepositoryNode extends SubscribeableViewNode {
);
}
if (this.view.config.showUpstreamStatus) {
if (status.hasConflicts) {
const mergeStatus = await Container.git.getMergeStatus(status);
if (mergeStatus != null) {
children.push(new MergeStatusNode(this.view, this, branch, mergeStatus));
}
} else if (this.view.config.showUpstreamStatus) {
if (status.upstream) {
if (!status.state.behind && !status.state.ahead) {
children.push(new BranchTrackingStatusNode(this.view, this, branch, status, 'same', true));

+ 3
- 0
src/views/nodes/viewNode.ts View File

@ -39,6 +39,9 @@ export enum ContextValues {
FileHistory = 'gitlens:history:file',
Folder = 'gitlens:folder',
LineHistory = 'gitlens:history:line',
Merge = 'gitlens:merge',
MergeCurrentChanges = 'gitlens:merge:current',
MergeIncomingChanges = 'gitlens:merge:incoming',
Message = 'gitlens:message',
Pager = 'gitlens:pager',
PullRequest = 'gitlens:pullrequest',

+ 70
- 8
src/views/viewCommands.ts View File

@ -30,6 +30,7 @@ import {
FileRevisionAsCommitNode,
FolderNode,
LineHistoryNode,
MergeConflictFileNode,
nodeSupportsClearing,
PageableViewNode,
PagerNode,
@ -764,8 +765,35 @@ export class ViewCommands {
}
@debug()
private openChanges(node: ViewRefFileNode | StatusFileNode) {
if (!(node instanceof ViewRefFileNode) && !(node instanceof StatusFileNode)) return;
private openChanges(node: ViewRefFileNode | MergeConflictFileNode | StatusFileNode) {
if (
!(node instanceof ViewRefFileNode) &&
!(node instanceof MergeConflictFileNode) &&
!(node instanceof StatusFileNode)
) {
return;
}
if (node instanceof MergeConflictFileNode) {
void executeCommand<DiffWithCommandArgs>(Commands.DiffWith, {
lhs: {
sha: 'MERGE_HEAD',
uri: GitUri.fromFile(node.file, node.repoPath, undefined, true),
},
rhs: {
sha: 'HEAD',
uri: GitUri.fromFile(node.file, node.repoPath),
},
repoPath: node.repoPath,
line: 0,
showOptions: {
preserveFocus: false,
preview: false,
},
});
return;
}
const command = node.getCommand();
if (command?.arguments == null) return;
@ -860,8 +888,14 @@ export class ViewCommands {
}
@debug()
private openChangesWithWorking(node: ViewRefFileNode | StatusFileNode) {
if (!(node instanceof ViewRefFileNode) && !(node instanceof StatusFileNode)) return Promise.resolve();
private async openChangesWithWorking(node: ViewRefFileNode | MergeConflictFileNode | StatusFileNode) {
if (
!(node instanceof ViewRefFileNode) &&
!(node instanceof MergeConflictFileNode) &&
!(node instanceof StatusFileNode)
) {
return Promise.resolve();
}
if (node instanceof StatusFileNode) {
return executeEditorCommand<DiffWithWorkingCommandArgs>(Commands.DiffWithWorking, undefined, {
@ -871,15 +905,37 @@ export class ViewCommands {
preview: true,
},
});
} else if (node instanceof MergeConflictFileNode) {
return executeEditorCommand<DiffWithWorkingCommandArgs>(Commands.DiffWithWorking, undefined, {
uri: node.baseUri,
showOptions: {
preserveFocus: true,
preview: true,
},
});
} else if (node instanceof FileRevisionAsCommitNode && node.commit.hasConflicts) {
const baseUri = await node.getConflictBaseUri();
if (baseUri != null) {
return executeEditorCommand<DiffWithWorkingCommandArgs>(Commands.DiffWithWorking, undefined, {
uri: baseUri,
showOptions: {
preserveFocus: true,
preview: true,
},
});
}
}
return GitActions.Commit.openChangesWithWorking(node.file, { repoPath: node.repoPath, ref: node.ref.ref });
}
@debug()
private openFile(node: ViewRefFileNode | StatusFileNode | FileHistoryNode | LineHistoryNode) {
private openFile(
node: ViewRefFileNode | MergeConflictFileNode | StatusFileNode | FileHistoryNode | LineHistoryNode,
) {
if (
!(node instanceof ViewRefFileNode) &&
!(node instanceof MergeConflictFileNode) &&
!(node instanceof StatusFileNode) &&
!(node instanceof FileHistoryNode) &&
!(node instanceof LineHistoryNode)
@ -911,7 +967,13 @@ export class ViewCommands {
@debug()
private openRevision(
node: CommitFileNode | FileRevisionAsCommitNode | ResultsFileNode | StashFileNode | StatusFileNode,
node:
| CommitFileNode
| FileRevisionAsCommitNode
| ResultsFileNode
| StashFileNode
| MergeConflictFileNode
| StatusFileNode,
options?: OpenFileAtRevisionCommandArgs,
) {
if (
@ -919,7 +981,7 @@ export class ViewCommands {
!(node instanceof FileRevisionAsCommitNode) &&
!(node instanceof ResultsFileNode) &&
!(node instanceof StashFileNode) &&
!(node instanceof ResultsFileNode) &&
!(node instanceof MergeConflictFileNode) &&
!(node instanceof StatusFileNode)
) {
return Promise.resolve();
@ -929,7 +991,7 @@ export class ViewCommands {
let uri = options.revisionUri;
if (uri == null) {
if (node instanceof ResultsFileNode) {
if (node instanceof ResultsFileNode || node instanceof MergeConflictFileNode) {
uri = GitUri.toRevisionUri(node.uri);
} else {
uri =

Loading…
Cancel
Save