diff --git a/extensions/git/package.json b/extensions/git/package.json index 8a003bdefb4..6e5deb004a1 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -136,6 +136,11 @@ "icon": "$(refresh)", "enablement": "!operationInProgress" }, + { + "command": "git.compareWithWorkspace", + "title": "%command.compareWithWorkspace%", + "category": "Git" + }, { "command": "git.openChange", "title": "%command.openChange%", @@ -1982,6 +1987,11 @@ "when": "scmProvider == git && scmResourceGroup == index", "group": "2_view@2" }, + { + "command": "git.compareWithWorkspace", + "when": "scmProvider == git && scmResourceGroup == index && scmResourceState == worktree", + "group": "worktree_diff" + }, { "command": "git.openFile2", "when": "scmProvider == git && scmResourceGroup == index && config.git.showInlineOpenFileAction && config.git.openDiffOnClick", @@ -2027,6 +2037,11 @@ "when": "scmProvider == git && scmResourceGroup == workingTree", "group": "inline@2" }, + { + "command": "git.compareWithWorkspace", + "when": "scmProvider == git && scmResourceGroup == workingTree && scmResourceState == worktree", + "group": "worktree_diff" + }, { "command": "git.openFile2", "when": "scmProvider == git && scmResourceGroup == workingTree && config.git.showInlineOpenFileAction && config.git.openDiffOnClick", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 8e2d58ee7a2..ae4159e566d 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -13,6 +13,7 @@ "command.openWorktree": "Open Worktree in Current Window", "command.openWorktreeInNewWindow": "Open Worktree in New Window", "command.refresh": "Refresh", + "command.compareWithWorkspace": "Compare with Workspace", "command.openChange": "Open Changes", "command.openAllChanges": "Open All Changes", "command.openFile": "Open File", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index aa825b87587..16a84672aa2 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1484,6 +1484,42 @@ export class CommandCenter { } } + @command('git.compareWithWorkspace') + async compareWithWorkspace(resource?: Resource): Promise { + if (!resource) { + return; + } + + const repository = this.model.getRepository(resource.resourceUri); + + if (!repository || !repository.dotGit.commonPath) { + return; + } + + const parentRepoRoot = path.dirname(repository.dotGit.commonPath); + const relPath = path.relative(repository.root, resource.resourceUri.fsPath); + const parentFileUri = Uri.file(path.join(parentRepoRoot, relPath)); + + const worktreeUri = resource.resourceUri; + + const baseUri = toGitUri(parentFileUri, 'HEAD'); + + await commands.executeCommand('_open.mergeEditor', { + base: baseUri, + input1: { + uri: parentFileUri, + title: l10n.t('Workspace'), + description: path.basename(parentRepoRoot) + }, + input2: { + uri: worktreeUri, + title: l10n.t('Worktree'), + description: path.basename(repository.root) + }, + output: parentFileUri + }); + } + @command('git.rename', { repository: true }) async rename(repository: Repository, fromUri: Uri | undefined): Promise { fromUri = fromUri ?? window.activeTextEditor?.document.uri; diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 197468b788b..58b310c6674 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -182,6 +182,7 @@ export class Resource implements SourceControlResourceState { get type(): Status { return this._type; } get original(): Uri { return this._resourceUri; } get renameResourceUri(): Uri | undefined { return this._renameResourceUri; } + get contextValue(): string | undefined { return this._repositoryKind; } private static Icons: any = { light: { @@ -310,6 +311,7 @@ export class Resource implements SourceControlResourceState { private _type: Status, private _useIcons: boolean, private _renameResourceUri?: Uri, + private _repositoryKind?: 'repository' | 'submodule' | 'worktree', ) { } async open(): Promise { @@ -328,7 +330,7 @@ export class Resource implements SourceControlResourceState { } clone(resourceGroupType?: ResourceGroupType) { - return new Resource(this._commandResolver, resourceGroupType ?? this._resourceGroupType, this._resourceUri, this._type, this._useIcons, this._renameResourceUri); + return new Resource(this._commandResolver, resourceGroupType ?? this._resourceGroupType, this._resourceUri, this._type, this._useIcons, this._renameResourceUri, this._repositoryKind); } } @@ -2511,12 +2513,12 @@ export class Repository implements Disposable { switch (raw.x + raw.y) { case '??': switch (untrackedChanges) { - case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons)); + case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons, undefined, this.kind)); case 'separate': return untrackedGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.UNTRACKED, useIcons)); default: return undefined; } case '!!': switch (untrackedChanges) { - case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons)); + case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons, undefined, this.kind)); case 'separate': return untrackedGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.IGNORED, useIcons)); default: return undefined; } @@ -2530,19 +2532,19 @@ export class Repository implements Disposable { } switch (raw.x) { - case 'M': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break; - case 'A': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break; - case 'D': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break; - case 'R': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break; - case 'C': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri)); break; + case 'M': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons, undefined, this.kind)); break; + case 'A': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons, undefined, this.kind)); break; + case 'D': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons, undefined, this.kind)); break; + case 'R': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri, this.kind)); break; + case 'C': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri, this.kind)); break; } switch (raw.y) { - case 'M': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break; - case 'D': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break; - case 'A': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break; - case 'R': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_RENAME, useIcons, renameUri)); break; - case 'T': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.TYPE_CHANGED, useIcons, renameUri)); break; + case 'M': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri, this.kind)); break; + case 'D': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri, this.kind)); break; + case 'A': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri, this.kind)); break; + case 'R': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_RENAME, useIcons, renameUri, this.kind)); break; + case 'T': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.TYPE_CHANGED, useIcons, renameUri, this.kind)); break; } return undefined;