From 3fff78b18aa9f125868f831b4ab5ab26c13de402 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 27 Oct 2025 23:37:10 +0100 Subject: [PATCH] Graph - add command to compare references (#273635) --- extensions/git/package.json | 15 +++++++++ extensions/git/package.nls.json | 1 + extensions/git/src/commands.ts | 59 +++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/extensions/git/package.json b/extensions/git/package.json index 9ff385ce77f..bc8b9d3d37b 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -514,6 +514,12 @@ "category": "Git", "enablement": "!operationInProgress" }, + { + "command": "git.graph.compareBranches", + "title": "%command.graphCompareBranches%", + "category": "Git", + "enablement": "!operationInProgress" + }, { "command": "git.deleteRemoteBranch", "title": "%command.deleteRemoteBranch%", @@ -1594,6 +1600,10 @@ "command": "git.graph.deleteBranch", "when": "false" }, + { + "command": "git.graph.compareBranches", + "when": "false" + }, { "command": "git.graph.deleteTag", "when": "false" @@ -2265,6 +2275,11 @@ "when": "scmProvider == git && scmHistoryItemRef =~ /^refs\\/heads\\/|^refs\\/remotes\\//", "group": "2_branch@2" }, + { + "command": "git.graph.compareBranches", + "when": "scmProvider == git && scmHistoryItemRef =~ /^refs\\/heads\\//", + "group": "2_branch@3" + }, { "command": "git.graph.deleteTag", "when": "scmProvider == git && scmHistoryItemRef =~ /^refs\\/tags\\//", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index ae4159e566d..dd41ad67f38 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -135,6 +135,7 @@ "command.graphCheckout": "Checkout", "command.graphCheckoutDetached": "Checkout (Detached)", "command.graphCherryPick": "Cherry Pick", + "command.graphCompareBranches": "Compare Branches...", "command.graphDeleteBranch": "Delete Branch", "command.graphDeleteTag": "Delete Tag", "command.blameToggleEditorDecoration": "Toggle Git Blame Editor Decoration", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index c57ae4606c0..4a59b05ee36 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -3114,6 +3114,65 @@ export class CommandCenter { await this._deleteBranch(repository, undefined, undefined, { remote: true }); } + @command('git.graph.compareBranches', { repository: true }) + async compareBranches(repository: Repository, historyItem?: SourceControlHistoryItem, historyItemRefId?: string): Promise { + const historyItemRef = historyItem?.references?.find(r => r.id === historyItemRefId); + if (!historyItemRefId || !historyItemRef) { + return; + } + + const config = workspace.getConfiguration('git'); + const showRefDetails = config.get('showReferenceDetails') === true; + + const getBranchPicks = async () => { + const refs = await repository.getRefs({ includeCommitDetails: showRefDetails }); + const processors = [ + new RefProcessor(RefType.Head, BranchItem), + new RefProcessor(RefType.Tag, BranchItem) + ]; + + const itemsProcessor = new RefItemsProcessor(repository, processors); + return itemsProcessor.processRefs(refs); + }; + + const placeHolder = l10n.t('Select a source reference to compare to'); + const sourceRef = await this.pickRef(getBranchPicks(), placeHolder); + + if (!(sourceRef instanceof BranchItem)) { + return; + } + + if (historyItemRefId === sourceRef.refId) { + window.showInformationMessage(l10n.t('The selected references are the same.')); + return; + } + + try { + const changes = await repository.diffTrees(historyItemRefId, sourceRef.refId); + + if (changes.length === 0) { + window.showInformationMessage(l10n.t('The selected references have no differences.')); + return; + } + + const resources = changes.map(change => toMultiFileDiffEditorUris(change, sourceRef.refId, historyItemRefId)); + + const title = `${sourceRef.ref.name} ↔ ${historyItemRef.name}`; + const multiDiffSourceUri = Uri.from({ + scheme: 'git-branch-compare', + path: `${repository.root}/${sourceRef.refId}..${historyItemRefId}` + }); + + await commands.executeCommand('_workbench.openMultiDiffEditor', { + multiDiffSourceUri, + title, + resources + }); + } catch (err) { + throw new Error(l10n.t('Failed to compare references: {0}', err.message ?? err)); + } + } + private async _deleteBranch(repository: Repository, remote: string | undefined, name: string | undefined, options: { remote: boolean; force?: boolean }): Promise { let run: (force?: boolean) => Promise;