Skip to content

Commit 885e673

Browse files
committed
Adds "merge changes" to files
1 parent 770da16 commit 885e673

File tree

6 files changed

+120
-6
lines changed

6 files changed

+120
-6
lines changed

contributions.json

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7683,6 +7683,23 @@
76837683
]
76847684
}
76857685
},
7686+
"gitlens.views.mergeChangesWithWorking": {
7687+
"label": "Merge Changes (Manually)...",
7688+
"menus": {
7689+
"view/item/context": [
7690+
{
7691+
"when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !listMultiSelection",
7692+
"group": "1_gitlens_actions",
7693+
"order": 2
7694+
},
7695+
{
7696+
"when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+committed\\b)|:results\\b)/ && !listMultiSelection",
7697+
"group": "8_gitlens_actions",
7698+
"order": 2
7699+
}
7700+
]
7701+
}
7702+
},
76867703
"gitlens.views.openBranchOnRemote": {
76877704
"label": "Open Branch on Remote",
76887705
"icon": "$(globe)",
@@ -9538,12 +9555,12 @@
95389555
{
95399556
"when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !listMultiSelection && !gitlens:hasVirtualFolders && !gitlens:readonly && !gitlens:untrusted",
95409557
"group": "1_gitlens_actions",
9541-
"order": 2
9558+
"order": 3
95429559
},
95439560
{
95449561
"when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+committed\\b)|:results\\b)/ && !listMultiSelection && !gitlens:hasVirtualFolders && !gitlens:readonly && !gitlens:untrusted",
95459562
"group": "8_gitlens_actions",
9546-
"order": 2
9563+
"order": 3
95479564
}
95489565
]
95499566
}

package.json

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8528,6 +8528,10 @@
85288528
"title": "Merge Branch into Current Branch...",
85298529
"enablement": "!operationInProgress"
85308530
},
8531+
{
8532+
"command": "gitlens.views.mergeChangesWithWorking",
8533+
"title": "Merge Changes (Manually)..."
8534+
},
85318535
{
85328536
"command": "gitlens.views.openBranchOnRemote",
85338537
"title": "Open Branch on Remote",
@@ -12274,6 +12278,10 @@
1227412278
"command": "gitlens.views.mergeBranchInto",
1227512279
"when": "false"
1227612280
},
12281+
{
12282+
"command": "gitlens.views.mergeChangesWithWorking",
12283+
"when": "false"
12284+
},
1227712285
{
1227812286
"command": "gitlens.views.openBranchOnRemote",
1227912287
"when": "false"
@@ -16791,10 +16799,15 @@
1679116799
"when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+(un)?staged\\b)/ && !listMultiSelection && !gitlens:hasVirtualFolders && !gitlens:readonly && !gitlens:untrusted",
1679216800
"group": "1_gitlens_actions@2"
1679316801
},
16802+
{
16803+
"command": "gitlens.views.mergeChangesWithWorking",
16804+
"when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !listMultiSelection",
16805+
"group": "1_gitlens_actions@2"
16806+
},
1679416807
{
1679516808
"command": "gitlens.views.restore",
1679616809
"when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+stashed\\b)/ && !listMultiSelection && !gitlens:hasVirtualFolders && !gitlens:readonly && !gitlens:untrusted",
16797-
"group": "1_gitlens_actions@2"
16810+
"group": "1_gitlens_actions@3"
1679816811
},
1679916812
{
1680016813
"command": "gitlens.views.openChanges",
@@ -16882,10 +16895,15 @@
1688216895
"when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+committed\\b)|:results\\b)/ && !listMultiSelection && !gitlens:hasVirtualFolders && !gitlens:readonly && !gitlens:untrusted",
1688316896
"group": "8_gitlens_actions@1"
1688416897
},
16898+
{
16899+
"command": "gitlens.views.mergeChangesWithWorking",
16900+
"when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+committed\\b)|:results\\b)/ && !listMultiSelection",
16901+
"group": "8_gitlens_actions@2"
16902+
},
1688516903
{
1688616904
"command": "gitlens.views.restore",
1688716905
"when": "viewItem =~ /gitlens:file\\b((?=.*?\\b\\+committed\\b)|:results\\b)/ && !listMultiSelection && !gitlens:hasVirtualFolders && !gitlens:readonly && !gitlens:untrusted",
16888-
"group": "8_gitlens_actions@2"
16906+
"group": "8_gitlens_actions@3"
1688916907
},
1689016908
{
1689116909
"command": "gitlens.views.stageDirectory",

src/constants.commands.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ export type ContributedCommands =
333333
| 'gitlens.views.loadAllChildren'
334334
| 'gitlens.views.loadMoreChildren'
335335
| 'gitlens.views.mergeBranchInto'
336+
| 'gitlens.views.mergeChangesWithWorking'
336337
| 'gitlens.views.openBranchOnRemote'
337338
| 'gitlens.views.openBranchOnRemote.multi'
338339
| 'gitlens.views.openChangedFileDiffs'

src/constants.commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ export type GlCommands = ContributedCommands | InternalGlCommands | GlCommandsDe
233233
export type GlPaletteCommands = ContributedPaletteCommands;
234234

235235
export type CoreCommands =
236+
| '_open.mergeEditor'
236237
| 'cursorMove'
237238
| 'editor.action.showHover'
238239
| 'editor.action.showReferences'

src/system/-webview/vscode.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,39 @@ export async function openDiffEditor(
368368
}
369369
}
370370

371+
type MergeEditorInputData = { uri: Uri; title?: string; detail?: string; description?: string };
372+
export type MergeEditorInputs = {
373+
base: Uri;
374+
input1: MergeEditorInputData;
375+
input2: MergeEditorInputData;
376+
output: Uri;
377+
};
378+
379+
export async function openMergeEditor(
380+
inputs: MergeEditorInputs,
381+
options?: TextDocumentShowOptions & { sourceViewColumn?: ViewColumn },
382+
): Promise<void> {
383+
try {
384+
if (options?.viewColumn === ViewColumn.Beside) {
385+
let column = (options?.sourceViewColumn ?? window.tabGroups.activeTabGroup?.viewColumn ?? 0) + 1;
386+
if (column > ViewColumn.Nine) {
387+
column = ViewColumn.One;
388+
}
389+
390+
if (window.tabGroups.all.some(g => g.viewColumn === column)) {
391+
await executeCoreCommand('workbench.action.focusRightGroup');
392+
} else {
393+
await executeCoreCommand('workbench.action.newGroupRight');
394+
}
395+
}
396+
397+
await executeCoreCommand('_open.mergeEditor', inputs);
398+
} catch (ex) {
399+
Logger.error(ex, 'openMergeEditor');
400+
debugger;
401+
}
402+
}
403+
371404
export async function openUrl(url: string): Promise<boolean>;
372405
export async function openUrl(url?: string): Promise<boolean | undefined>;
373406
export async function openUrl(url?: string): Promise<boolean | undefined> {

src/views/viewCommands.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ import {
4949
} from '../system/-webview/command';
5050
import { configuration } from '../system/-webview/configuration';
5151
import { setContext } from '../system/-webview/context';
52-
import type { OpenWorkspaceLocation } from '../system/-webview/vscode';
53-
import { openUrl, openWorkspace, revealInFileExplorer } from '../system/-webview/vscode';
52+
import type { MergeEditorInputs, OpenWorkspaceLocation } from '../system/-webview/vscode';
53+
import { openMergeEditor, openUrl, openWorkspace, revealInFileExplorer } from '../system/-webview/vscode';
5454
import { filterMap } from '../system/array';
5555
import { log } from '../system/decorators/log';
5656
import { partial, runSequentially } from '../system/function';
5757
import { join, map } from '../system/iterable';
5858
import { lazy } from '../system/lazy';
5959
import { basename } from '../system/path';
60+
import { getSettledValue } from '../system/promise';
6061
import { DeepLinkActionType } from '../uris/deepLinks/deepLink';
6162
import type { LaunchpadItemNode } from './launchpadView';
6263
import type { RepositoryFolderNode } from './nodes/abstract/repositoryFolderNode';
@@ -281,6 +282,7 @@ export class ViewCommands implements Disposable {
281282
registerViewCommand('gitlens.views.openChanges', this.openChanges, this),
282283
registerViewCommand('gitlens.views.openChangesWithMergeBase', this.openChangesWithMergeBase, this),
283284
registerViewCommand('gitlens.views.openChangesWithWorking', this.openChangesWithWorking, this),
285+
registerViewCommand('gitlens.views.mergeChangesWithWorking', this.mergeChangesWithWorking, this),
284286
registerViewCommand(
285287
'gitlens.views.openPreviousChangesWithWorking',
286288
this.openPreviousChangesWithWorking,
@@ -1538,6 +1540,48 @@ export class ViewCommands implements Disposable {
15381540
return CommitActions.openCommitChangesWithWorking(this.container, node.commit, individually, options);
15391541
}
15401542

1543+
private async mergeChangesWithWorking(node: ViewRefFileNode) {
1544+
if (!(node instanceof ViewRefFileNode)) return Promise.resolve();
1545+
1546+
const repo = this.container.git.getRepository(node.repoPath);
1547+
if (repo == null) return Promise.resolve();
1548+
1549+
const nodeUri = await this.container.git.getBestRevisionUri(node.repoPath, node.file.path, node.ref.ref);
1550+
if (nodeUri == null) return Promise.resolve();
1551+
1552+
const [mergeBaseResult, workingUriResult] = await Promise.allSettled([
1553+
repo.git.refs().getMergeBase(node.ref.ref, 'HEAD'),
1554+
this.container.git.getWorkingUri(node.repoPath, node.uri),
1555+
]);
1556+
1557+
const workingUri = getSettledValue(workingUriResult);
1558+
if (workingUri == null) {
1559+
void window.showWarningMessage('Unable to open the merge editor, no working file found');
1560+
return Promise.resolve();
1561+
}
1562+
1563+
const mergeBase = getSettledValue(mergeBaseResult);
1564+
const baseUri =
1565+
mergeBase != null
1566+
? await this.container.git.getBestRevisionUri(node.repoPath, node.file.path, mergeBase)
1567+
: undefined;
1568+
1569+
const inputs: MergeEditorInputs = {
1570+
base: baseUri ?? nodeUri,
1571+
input1: {
1572+
uri: nodeUri,
1573+
title: node.ref.name,
1574+
},
1575+
input2: {
1576+
uri: workingUri,
1577+
title: 'Working Tree',
1578+
},
1579+
output: workingUri,
1580+
};
1581+
1582+
return openMergeEditor(inputs);
1583+
}
1584+
15411585
@log()
15421586
private async openChangesWithMergeBase(node: ResultsFileNode) {
15431587
if (!node.is('results-file')) return Promise.resolve();

0 commit comments

Comments
 (0)