Enable users to view and apply changes from worktree to main repo, per file (#263927)

* enable compare with workspace command

* add context to command

* clean up
This commit is contained in:
Christy 😺
2025-09-02 06:28:07 -07:00
committed by GitHub
parent 05c2fd5932
commit f562c9d3e8
4 changed files with 67 additions and 13 deletions

View File

@@ -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",

View File

@@ -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",

View File

@@ -1484,6 +1484,42 @@ export class CommandCenter {
}
}
@command('git.compareWithWorkspace')
async compareWithWorkspace(resource?: Resource): Promise<void> {
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<void> {
fromUri = fromUri ?? window.activeTextEditor?.document.uri;

View File

@@ -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<void> {
@@ -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;