From bd0060d17322a6ad471202e3268ee3b382891def Mon Sep 17 00:00:00 2001
From: Eric Amodio <eamodio@gmail.com>
Date: Mon, 26 Sep 2022 03:05:15 -0400
Subject: [PATCH] Adds more context menus actions

---
 package.json                            | 249 ++++++++++++++++++++++++++++++--
 src/plus/webviews/graph/graphWebview.ts | 231 +++++++++++++++++++++++++++--
 2 files changed, 452 insertions(+), 28 deletions(-)

diff --git a/package.json b/package.json
index b1a31f9..874247a 100644
--- a/package.json
+++ b/package.json
@@ -6251,30 +6251,61 @@
 				"category": "GitLens"
 			},
 			{
-				"command": "gitlens.graph.switchToAnotherBranch",
-				"title": "Switch to Another Branch...",
+				"command": "gitlens.graph.createBranch",
+				"title": "Create Branch...",
 				"category": "GitLens",
-				"icon": "$(gitlens-switch)"
+				"icon": "$(add)"
 			},
 			{
-				"command": "gitlens.graph.switchToBranch",
-				"title": "Switch to Branch...",
+				"command": "gitlens.graph.deleteBranch",
+				"title": "Delete Branch...",
 				"category": "GitLens",
-				"icon": "$(gitlens-switch)"
+				"icon": "$(trash)"
 			},
 			{
-				"command": "gitlens.graph.switchToCommit",
-				"title": "Switch to Commit...",
+				"command": "gitlens.graph.openBranchOnRemote",
+				"title": "Open Branch on Remote",
+				"category": "GitLens",
+				"icon": "$(globe)"
+			},
+			{
+				"command": "gitlens.graph.mergeBranchInto",
+				"title": "Merge Branch into Current Branch...",
+				"category": "GitLens"
+			},
+			{
+				"command": "gitlens.graph.rebaseOntoBranch",
+				"title": "Rebase Current Branch onto Branch...",
+				"category": "GitLens"
+			},
+			{
+				"command": "gitlens.graph.rebaseOntoUpstream",
+				"title": "Rebase Current Branch onto Upstream...",
+				"category": "GitLens"
+			},
+			{
+				"command": "gitlens.graph.renameBranch",
+				"title": "Rename Branch...",
+				"category": "GitLens"
+			},
+			{
+				"command": "gitlens.graph.switchToAnotherBranch",
+				"title": "Switch to Another Branch...",
 				"category": "GitLens",
 				"icon": "$(gitlens-switch)"
 			},
 			{
-				"command": "gitlens.graph.switchToTag",
-				"title": "Switch to Tag...",
+				"command": "gitlens.graph.switchToBranch",
+				"title": "Switch to Branch...",
 				"category": "GitLens",
 				"icon": "$(gitlens-switch)"
 			},
 			{
+				"command": "gitlens.graph.cherryPick",
+				"title": "Cherry Pick Commit...",
+				"category": "GitLens"
+			},
+			{
 				"command": "gitlens.graph.rebaseOntoCommit",
 				"title": "Rebase Current Branch onto Commit...",
 				"category": "GitLens"
@@ -6295,10 +6326,58 @@
 				"category": "GitLens"
 			},
 			{
+				"command": "gitlens.graph.switchToCommit",
+				"title": "Switch to Commit...",
+				"category": "GitLens",
+				"icon": "$(gitlens-switch)"
+			},
+			{
 				"command": "gitlens.graph.undoCommit",
 				"title": "Undo Commit",
 				"category": "GitLens",
 				"icon": "$(discard)"
+			},
+			{
+				"command": "gitlens.graph.applyStash",
+				"title": "Apply Stash",
+				"category": "GitLens",
+				"icon": "$(gitlens-stash-pop)"
+			},
+			{
+				"command": "gitlens.graph.deleteStash",
+				"title": "Delete Stash...",
+				"category": "GitLens",
+				"icon": "$(trash)"
+			},
+			{
+				"command": "gitlens.graph.createTag",
+				"title": "Create Tag...",
+				"category": "GitLens",
+				"icon": "$(add)"
+			},
+			{
+				"command": "gitlens.graph.deleteTag",
+				"title": "Delete Tag...",
+				"category": "GitLens",
+				"icon": "$(trash)"
+			},
+			{
+				"command": "gitlens.graph.switchToTag",
+				"title": "Switch to Tag...",
+				"category": "GitLens",
+				"icon": "$(gitlens-switch)"
+			},
+			{
+				"command": "gitlens.graph.createWorktree",
+				"title": "Create Worktree...",
+				"category": "GitLens",
+				"icon": "$(add)"
+			},
+			{
+				"command": "gitlens.graph.createPullRequest",
+				"title": "Create Pull Request...",
+				"category": "GitLens",
+				"icon": "$(git-pull-request-create)"
 			}
 		],
 		"icons": {
@@ -8087,19 +8166,43 @@
 					"when": "false"
 				},
 				{
-					"command": "gitlens.graph.switchToAnotherBranch",
+					"command": "gitlens.graph.createBranch",
 					"when": "false"
 				},
 				{
-					"command": "gitlens.graph.switchToBranch",
+					"command": "gitlens.graph.deleteBranch",
 					"when": "false"
 				},
 				{
-					"command": "gitlens.graph.switchToCommit",
+					"command": "gitlens.graph.openBranchOnRemote",
 					"when": "false"
 				},
 				{
-					"command": "gitlens.graph.switchToTag",
+					"command": "gitlens.graph.mergeBranchInto",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.rebaseOntoBranch",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.rebaseOntoUpstream",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.renameBranch",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.switchToAnotherBranch",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.switchToBranch",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.cherryPick",
 					"when": "false"
 				},
 				{
@@ -8119,10 +8222,42 @@
 					"when": "false"
 				},
 				{
+					"command": "gitlens.graph.switchToCommit",
+					"when": "false"
+				},
+				{
 					"command": "gitlens.graph.undoCommit",
 					"when": "false"
 				},
 				{
+					"command": "gitlens.graph.applyStash",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.deleteStash",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.createTag",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.deleteTag",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.switchToTag",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.createWorktree",
+					"when": "false"
+				},
+				{
+					"command": "gitlens.graph.createPullRequest",
+					"when": "false"
+				},
+				{
 					"command": "gitlens.enableDebugLogging",
 					"when": "config.gitlens.outputLevel != debug"
 				},
@@ -10565,6 +10700,62 @@
 					"group": "1_gitlens_actions@1"
 				},
 				{
+					"command": "gitlens.graph.mergeBranchInto",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)/",
+					"group": "1_gitlens_actions@3"
+				},
+				{
+					"command": "gitlens.graph.rebaseOntoBranch",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)/",
+					"group": "1_gitlens_actions@4"
+				},
+				{
+					"command": "gitlens.graph.rebaseOntoUpstream",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+current\\b)(?=.*?\\b\\+tracking\\b)/",
+					"group": "1_gitlens_actions@4"
+				},
+				{
+					"command": "gitlens.graph.renameBranch",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b/",
+					"group": "1_gitlens_actions@5"
+				},
+				{
+					"command": "gitlens.graph.deleteBranch",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)/",
+					"group": "1_gitlens_actions@6"
+				},
+				{
+					"command": "gitlens.graph.createBranch",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b/",
+					"group": "1_gitlens_actions_@7"
+				},
+				{
+					"command": "gitlens.graph.createTag",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b/",
+					"group": "1_gitlens_actions_@8"
+				},
+				{
+					"command": "gitlens.graph.createWorktree",
+					"when": "!gitlens:readonly && webviewItem =~ /gitlens:branch\\b/",
+					"group": "1_gitlens_actions_@9"
+				},
+				{
+					"command": "gitlens.graph.createPullRequest",
+					"when": "gitlens:hasRemotes && gitlens:action:createPullRequest && webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(tracking|remote)\\b)/",
+					"group": "1_gitlens_actions_@10"
+				},
+				{
+					"command": "gitlens.graph.openBranchOnRemote",
+					"when": "gitlens:hasRemotes && webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(tracking|remote)\\b)/",
+					"group": "2_gitlens_quickopen@1",
+					"alt": "gitlens.copyRemoteBranchUrl"
+				},
+				{
+					"command": "gitlens.graph.cherryPick",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b(?!.*?\\b\\+current\\b)/",
+					"group": "1_gitlens_actions@1"
+				},
+				{
 					"command": "gitlens.graph.undoCommit",
 					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b(?=.*?\\b\\+HEAD\\b)/",
 					"group": "1_gitlens_actions@1"
@@ -10595,9 +10786,39 @@
 					"group": "1_gitlens_actions@7"
 				},
 				{
+					"command": "gitlens.graph.createBranch",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b/",
+					"group": "1_gitlens_actions_1@1"
+				},
+				{
+					"command": "gitlens.graph.createTag",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b/",
+					"group": "1_gitlens_actions_1@2"
+				},
+				{
+					"command": "gitlens.graph.applyStash",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem == gitlens:stash",
+					"group": "1_gitlens_actions@1"
+				},
+				{
+					"command": "gitlens.graph.deleteStash",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem == gitlens:stash",
+					"group": "1_gitlens_actions@2"
+				},
+				{
 					"command": "gitlens.graph.switchToTag",
 					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:tag\\b/",
 					"group": "1_gitlens_actions@1"
+				},
+				{
+					"command": "gitlens.graph.deleteTag",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem == gitlens:tag",
+					"group": "1_gitlens_actions@2"
+				},
+				{
+					"command": "gitlens.graph.createBranch",
+					"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:tag\\b/",
+					"group": "1_gitlens_actions@3"
 				}
 			],
 			"gitlens/commit/browse": [
diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts
index 4ed7b99..bf941f2 100644
--- a/src/plus/webviews/graph/graphWebview.ts
+++ b/src/plus/webviews/graph/graphWebview.ts
@@ -1,6 +1,8 @@
 import type { ColorTheme, ConfigurationChangeEvent, Disposable, Event, StatusBarItem } from 'vscode';
 import { CancellationTokenSource, EventEmitter, MarkdownString, StatusBarAlignment, ViewColumn, window } from 'vscode';
+import type { CreatePullRequestActionContext } from '../../../api/gitlens';
 import { getAvatarUri } from '../../../avatars';
+import type { OpenBranchOnRemoteCommandArgs } from '../../../commands';
 import { parseCommandContext } from '../../../commands/base';
 import { GitActions } from '../../../commands/gitCommands.actions';
 import { configuration } from '../../../configuration';
@@ -22,7 +24,7 @@ import type { Repository, RepositoryChangeEvent } from '../../../git/models/repo
 import { RepositoryChange, RepositoryChangeComparisonMode } from '../../../git/models/repository';
 import type { GitSearch } from '../../../git/search';
 import { getSearchQueryComparisonKey } from '../../../git/search';
-import { executeCoreGitCommand, registerCommand } from '../../../system/command';
+import { executeActionCommand, executeCommand, executeCoreGitCommand, registerCommand } from '../../../system/command';
 import { gate } from '../../../system/decorators/gate';
 import { debug } from '../../../system/decorators/log';
 import type { Deferrable } from '../../../system/function';
@@ -202,15 +204,35 @@ export class GraphWebview extends WebviewBase<State> {
 	protected override registerCommands(): Disposable[] {
 		return [
 			registerCommand(Commands.RefreshGraphPage, () => this.refresh(true)),
+			registerCommand('gitlens.graph.createBranch', this.createBranch, this),
+			registerCommand('gitlens.graph.deleteBranch', this.deleteBranch, this),
+			registerCommand('gitlens.graph.openBranchOnRemote', this.openBranchOnRemote, this),
+			registerCommand('gitlens.graph.mergeBranchInto', this.mergeBranchInto, this),
+			registerCommand('gitlens.graph.rebaseOntoBranch', this.rebase, this),
+			registerCommand('gitlens.graph.rebaseOntoUpstream', this.rebaseToRemote, this),
+			registerCommand('gitlens.graph.renameBranch', this.renameBranch, this),
+
 			registerCommand('gitlens.graph.switchToAnotherBranch', this.switchToAnother, this),
 			registerCommand('gitlens.graph.switchToBranch', this.switchTo, this),
-			registerCommand('gitlens.graph.undoCommit', this.undoCommit, this),
-			registerCommand('gitlens.graph.revert', this.revertCommit, this),
-			registerCommand('gitlens.graph.resetToCommit', this.resetToCommit, this),
-			registerCommand('gitlens.graph.resetCommit', this.resetCommit, this),
+
+			registerCommand('gitlens.graph.cherryPick', this.cherryPick, this),
 			registerCommand('gitlens.graph.rebaseOntoCommit', this.rebase, this),
+			registerCommand('gitlens.graph.resetCommit', this.resetCommit, this),
+			registerCommand('gitlens.graph.resetToCommit', this.resetToCommit, this),
+			registerCommand('gitlens.graph.revert', this.revertCommit, this),
 			registerCommand('gitlens.graph.switchToCommit', this.switchTo, this),
+			registerCommand('gitlens.graph.undoCommit', this.undoCommit, this),
+
+			registerCommand('gitlens.graph.applyStash', this.applyStash, this),
+			registerCommand('gitlens.graph.deleteStash', this.deleteStash, this),
+
+			registerCommand('gitlens.graph.createTag', this.createTag, this),
+			registerCommand('gitlens.graph.deleteTag', this.deleteTag, this),
 			registerCommand('gitlens.graph.switchToTag', this.switchTo, this),
+
+			registerCommand('gitlens.graph.createWorktree', this.createWorktree, this),
+
+			registerCommand('gitlens.graph.createPullRequest', this.createPullRequest, this),
 		];
 	}
 
@@ -816,6 +838,49 @@ export class GraphWebview extends WebviewBase<State> {
 	}
 
 	@debug()
+	private createBranch(item: GraphItemContext) {
+		if (isGraphItemRefContext(item)) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Branch.create(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private deleteBranch(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'branch')) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Branch.remove(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private mergeBranchInto(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'branch')) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.merge(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private openBranchOnRemote(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'branch')) {
+			const { ref } = item.webviewItemValue;
+			return executeCommand<OpenBranchOnRemoteCommandArgs>(Commands.OpenBranchOnRemote, {
+				branch: ref.name,
+				remote: ref.upstream?.name,
+			});
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
 	private rebase(item: GraphItemContext) {
 		if (isGraphItemRefContext(item)) {
 			const { ref } = item.webviewItemValue;
@@ -826,10 +891,49 @@ export class GraphWebview extends WebviewBase<State> {
 	}
 
 	@debug()
+	private rebaseToRemote(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'branch')) {
+			const { ref } = item.webviewItemValue;
+			if (ref.upstream != null) {
+				return GitActions.rebase(
+					ref.repoPath,
+					GitReference.create(ref.upstream.name, ref.repoPath, {
+						refType: 'branch',
+						name: ref.upstream.name,
+						remote: true,
+					}),
+				);
+			}
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private renameBranch(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'branch')) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Branch.rename(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private cherryPick(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'revision')) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.cherryPick(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
 	private resetCommit(item: GraphItemContext) {
-		if (isGraphItemRefContext(item) && item.webviewItemValue.ref.refType === 'revision') {
+		if (isGraphItemRefContext(item, 'revision')) {
 			const { ref } = item.webviewItemValue;
-			return GitActions.revert(
+			return GitActions.reset(
 				ref.repoPath,
 				GitReference.create(`${ref.ref}^`, ref.repoPath, {
 					refType: 'revision',
@@ -844,7 +948,7 @@ export class GraphWebview extends WebviewBase<State> {
 
 	@debug()
 	private resetToCommit(item: GraphItemContext) {
-		if (isGraphItemRefContext(item) && item.webviewItemValue.ref.refType === 'revision') {
+		if (isGraphItemRefContext(item, 'revision')) {
 			const { ref } = item.webviewItemValue;
 			return GitActions.reset(ref.repoPath, ref);
 		}
@@ -854,7 +958,7 @@ export class GraphWebview extends WebviewBase<State> {
 
 	@debug()
 	private revertCommit(item: GraphItemContext) {
-		if (isGraphItemRefContext(item) && item.webviewItemValue.ref.refType === 'revision') {
+		if (isGraphItemRefContext(item, 'revision')) {
 			const { ref } = item.webviewItemValue;
 			return GitActions.revert(ref.repoPath, ref);
 		}
@@ -884,8 +988,8 @@ export class GraphWebview extends WebviewBase<State> {
 
 	@debug()
 	private async undoCommit(item: GraphItemContext) {
-		if (isGraphItemRefContext(item) && item.webviewItemValue.ref.refType === 'revision') {
-			const ref = item.webviewItemValue.ref;
+		if (isGraphItemRefContext(item, 'revision')) {
+			const { ref } = item.webviewItemValue;
 			const repo = await this.container.git.getOrOpenScmRepository(ref.repoPath);
 			const commit = await repo?.getCommit('HEAD');
 
@@ -905,6 +1009,93 @@ export class GraphWebview extends WebviewBase<State> {
 
 		return Promise.resolve();
 	}
+
+	@debug()
+	private applyStash(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'stash')) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Stash.apply(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private deleteStash(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'stash')) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Stash.drop(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private async createTag(item: GraphItemContext) {
+		if (isGraphItemRefContext(item)) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Tag.create(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private deleteTag(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'tag')) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Tag.remove(ref.repoPath, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private async createWorktree(item: GraphItemContext) {
+		if (isGraphItemRefContext(item)) {
+			const { ref } = item.webviewItemValue;
+			return GitActions.Worktree.create(ref.repoPath, undefined, ref);
+		}
+
+		return Promise.resolve();
+	}
+
+	@debug()
+	private async createPullRequest(item: GraphItemContext) {
+		if (isGraphItemRefContext(item, 'branch')) {
+			const { ref } = item.webviewItemValue;
+
+			const repo = this.container.git.getRepository(ref.repoPath);
+			const branch = await repo?.getBranch(ref.name);
+			const remote = await branch?.getRemote();
+
+			return executeActionCommand<CreatePullRequestActionContext>('createPullRequest', {
+				repoPath: ref.repoPath,
+				remote:
+					remote != null
+						? {
+								name: remote.name,
+								provider:
+									remote.provider != null
+										? {
+												id: remote.provider.id,
+												name: remote.provider.name,
+												domain: remote.provider.domain,
+										  }
+										: undefined,
+								url: remote.url,
+						  }
+						: undefined,
+				branch: {
+					name: ref.name,
+					upstream: ref.upstream?.name,
+					isRemote: ref.remote,
+				},
+			});
+		}
+
+		return Promise.resolve();
+	}
 }
 
 function formatRepositories(repositories: Repository[]): GraphRepository[] {
@@ -919,7 +1110,7 @@ function formatRepositories(repositories: Repository[]): GraphRepository[] {
 }
 
 export type GraphItemContext = WebviewItemContext<GraphItemContextValue>;
-export type GraphItemRefContext = WebviewItemContext<GraphItemRefContextValue>;
+export type GraphItemRefContext<T = GraphItemRefContextValue> = WebviewItemContext<T>;
 export type GraphItemRefContextValue =
 	| GraphBranchContextValue
 	| GraphCommitContextValue
@@ -962,8 +1153,20 @@ function isGraphItemContext(item: unknown): item is GraphItemContext {
 	return isWebviewItemContext(item) && item.webview === 'gitlens.graph';
 }
 
-function isGraphItemRefContext(item: unknown): item is GraphItemRefContext {
+function isGraphItemRefContext(item: unknown): item is GraphItemRefContext;
+function isGraphItemRefContext(item: unknown, refType: 'branch'): item is GraphItemRefContext<GraphBranchContextValue>;
+function isGraphItemRefContext(
+	item: unknown,
+	refType: 'revision',
+): item is GraphItemRefContext<GraphCommitContextValue>;
+function isGraphItemRefContext(item: unknown, refType: 'stash'): item is GraphItemRefContext<GraphStashContextValue>;
+function isGraphItemRefContext(item: unknown, refType: 'tag'): item is GraphItemRefContext<GraphTagContextValue>;
+function isGraphItemRefContext(item: unknown, refType?: GitReference['refType']): item is GraphItemRefContext {
 	if (item == null) return false;
 
-	return isGraphItemContext(item) && 'ref' in item.webviewItemValue;
+	return (
+		isGraphItemContext(item) &&
+		'ref' in item.webviewItemValue &&
+		(refType == null || item.webviewItemValue.ref.refType === refType)
+	);
 }