Skip to content

Commit f562c9d

Browse files
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
1 parent 05c2fd5 commit f562c9d

File tree

4 files changed

+67
-13
lines changed

4 files changed

+67
-13
lines changed

extensions/git/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@
136136
"icon": "$(refresh)",
137137
"enablement": "!operationInProgress"
138138
},
139+
{
140+
"command": "git.compareWithWorkspace",
141+
"title": "%command.compareWithWorkspace%",
142+
"category": "Git"
143+
},
139144
{
140145
"command": "git.openChange",
141146
"title": "%command.openChange%",
@@ -1982,6 +1987,11 @@
19821987
"when": "scmProvider == git && scmResourceGroup == index",
19831988
"group": "2_view@2"
19841989
},
1990+
{
1991+
"command": "git.compareWithWorkspace",
1992+
"when": "scmProvider == git && scmResourceGroup == index && scmResourceState == worktree",
1993+
"group": "worktree_diff"
1994+
},
19851995
{
19861996
"command": "git.openFile2",
19871997
"when": "scmProvider == git && scmResourceGroup == index && config.git.showInlineOpenFileAction && config.git.openDiffOnClick",
@@ -2027,6 +2037,11 @@
20272037
"when": "scmProvider == git && scmResourceGroup == workingTree",
20282038
"group": "inline@2"
20292039
},
2040+
{
2041+
"command": "git.compareWithWorkspace",
2042+
"when": "scmProvider == git && scmResourceGroup == workingTree && scmResourceState == worktree",
2043+
"group": "worktree_diff"
2044+
},
20302045
{
20312046
"command": "git.openFile2",
20322047
"when": "scmProvider == git && scmResourceGroup == workingTree && config.git.showInlineOpenFileAction && config.git.openDiffOnClick",

extensions/git/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"command.openWorktree": "Open Worktree in Current Window",
1414
"command.openWorktreeInNewWindow": "Open Worktree in New Window",
1515
"command.refresh": "Refresh",
16+
"command.compareWithWorkspace": "Compare with Workspace",
1617
"command.openChange": "Open Changes",
1718
"command.openAllChanges": "Open All Changes",
1819
"command.openFile": "Open File",

extensions/git/src/commands.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,42 @@ export class CommandCenter {
14841484
}
14851485
}
14861486

1487+
@command('git.compareWithWorkspace')
1488+
async compareWithWorkspace(resource?: Resource): Promise<void> {
1489+
if (!resource) {
1490+
return;
1491+
}
1492+
1493+
const repository = this.model.getRepository(resource.resourceUri);
1494+
1495+
if (!repository || !repository.dotGit.commonPath) {
1496+
return;
1497+
}
1498+
1499+
const parentRepoRoot = path.dirname(repository.dotGit.commonPath);
1500+
const relPath = path.relative(repository.root, resource.resourceUri.fsPath);
1501+
const parentFileUri = Uri.file(path.join(parentRepoRoot, relPath));
1502+
1503+
const worktreeUri = resource.resourceUri;
1504+
1505+
const baseUri = toGitUri(parentFileUri, 'HEAD');
1506+
1507+
await commands.executeCommand('_open.mergeEditor', {
1508+
base: baseUri,
1509+
input1: {
1510+
uri: parentFileUri,
1511+
title: l10n.t('Workspace'),
1512+
description: path.basename(parentRepoRoot)
1513+
},
1514+
input2: {
1515+
uri: worktreeUri,
1516+
title: l10n.t('Worktree'),
1517+
description: path.basename(repository.root)
1518+
},
1519+
output: parentFileUri
1520+
});
1521+
}
1522+
14871523
@command('git.rename', { repository: true })
14881524
async rename(repository: Repository, fromUri: Uri | undefined): Promise<void> {
14891525
fromUri = fromUri ?? window.activeTextEditor?.document.uri;

extensions/git/src/repository.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export class Resource implements SourceControlResourceState {
182182
get type(): Status { return this._type; }
183183
get original(): Uri { return this._resourceUri; }
184184
get renameResourceUri(): Uri | undefined { return this._renameResourceUri; }
185+
get contextValue(): string | undefined { return this._repositoryKind; }
185186

186187
private static Icons: any = {
187188
light: {
@@ -310,6 +311,7 @@ export class Resource implements SourceControlResourceState {
310311
private _type: Status,
311312
private _useIcons: boolean,
312313
private _renameResourceUri?: Uri,
314+
private _repositoryKind?: 'repository' | 'submodule' | 'worktree',
313315
) { }
314316

315317
async open(): Promise<void> {
@@ -328,7 +330,7 @@ export class Resource implements SourceControlResourceState {
328330
}
329331

330332
clone(resourceGroupType?: ResourceGroupType) {
331-
return new Resource(this._commandResolver, resourceGroupType ?? this._resourceGroupType, this._resourceUri, this._type, this._useIcons, this._renameResourceUri);
333+
return new Resource(this._commandResolver, resourceGroupType ?? this._resourceGroupType, this._resourceUri, this._type, this._useIcons, this._renameResourceUri, this._repositoryKind);
332334
}
333335
}
334336

@@ -2511,12 +2513,12 @@ export class Repository implements Disposable {
25112513

25122514
switch (raw.x + raw.y) {
25132515
case '??': switch (untrackedChanges) {
2514-
case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons));
2516+
case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons, undefined, this.kind));
25152517
case 'separate': return untrackedGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.UNTRACKED, useIcons));
25162518
default: return undefined;
25172519
}
25182520
case '!!': switch (untrackedChanges) {
2519-
case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons));
2521+
case 'mixed': return workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons, undefined, this.kind));
25202522
case 'separate': return untrackedGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.IGNORED, useIcons));
25212523
default: return undefined;
25222524
}
@@ -2530,19 +2532,19 @@ export class Repository implements Disposable {
25302532
}
25312533

25322534
switch (raw.x) {
2533-
case 'M': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break;
2534-
case 'A': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
2535-
case 'D': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
2536-
case 'R': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
2537-
case 'C': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri)); break;
2535+
case 'M': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons, undefined, this.kind)); break;
2536+
case 'A': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons, undefined, this.kind)); break;
2537+
case 'D': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons, undefined, this.kind)); break;
2538+
case 'R': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri, this.kind)); break;
2539+
case 'C': indexGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri, this.kind)); break;
25382540
}
25392541

25402542
switch (raw.y) {
2541-
case 'M': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break;
2542-
case 'D': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break;
2543-
case 'A': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break;
2544-
case 'R': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_RENAME, useIcons, renameUri)); break;
2545-
case 'T': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.TYPE_CHANGED, useIcons, renameUri)); break;
2543+
case 'M': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri, this.kind)); break;
2544+
case 'D': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri, this.kind)); break;
2545+
case 'A': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri, this.kind)); break;
2546+
case 'R': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_RENAME, useIcons, renameUri, this.kind)); break;
2547+
case 'T': workingTreeGroup.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.TYPE_CHANGED, useIcons, renameUri, this.kind)); break;
25462548
}
25472549

25482550
return undefined;

0 commit comments

Comments
 (0)