fix(vcs): show branch actions in the Git Log commit menu (#1852)

Right-clicking a commit with branch labels offered commit actions only. The menu now has a Branch 'name' submenu with the existing branch actions for each branch at that commit other than the current one, grouped under Branches when there are more than two, and keeps Rebase onto Selected Commit for commits without branches. The actions run against the commit's repository in a multi-repository project.

Co-authored-by: shohruh-genius <[email protected]>
Цей коміт міститься в:
Shohruh Ismoilovтаshohruh-genius authored and GitHub committed 2026-11-07 10:37:24 +08:00
1 джерело 9298be8798
коміт 7e7da950fc
7 files changed
+132 -13

No files matched your search

+20 -8
Переглянути файл
@@ -1121,7 +1121,9 @@ export function commitMenu(c: Commit, selection: Commit[] = [c]): MenuItem[] {
{ label: "Browse Repository at Revision", run: () => browseRepositoryAt(c) },
];
const many = selection.length > 1 && selection.some((x) => commitKey(x) === commitKey(c));
const head = (commitRepo(c) ? useVcs.getState().heads[commitRepo(c)!]?.head : useVcs.getState().branch?.head) ?? null;
const repo = commitRepo(c);
const vcs = useVcs.getState();
const head = (repo ? vcs.heads[repo]?.head : vcs.branch?.head) ?? null;
const { outgoing } = useGitLog.getState();
const pushed = (x: Commit) =>
commitRepo(x) === undefined ? !!outgoing && !outgoing.has(x.id) : isPushed(commitKey(x));
@@ -1148,6 +1150,22 @@ export function commitMenu(c: Commit, selection: Commit[] = [c]): MenuItem[] {
((commitRepo(c) === undefined ? !!outgoing : useGitLog.getState().tracked.has(commitRepo(c) ?? ""))
? !!outgoing?.has(commitKey(c))
: true);
const branches = ((c as RepoCommit).refBranches ?? []).filter((branch) => !branch.current);
const branchActions: MenuItem[] = branches.map((branch) => {
const menu = branchMenu(branch, head);
return {
label: tx`Branch '${branch.name}'`,
submenu: repo ? inRepo(repo, menu) : menu,
};
});
if (!branchActions.length)
branchActions.push({
kind: "action",
action: "vcs.log.rebaseOntoCommit",
arg: c,
label: tx`Rebase '${head ?? "HEAD"}' onto Selected Commit`,
disabled: !head,
});
return [
{ kind: "action", action: "vcs.log.copyRevision", arg: c },
{
@@ -1173,13 +1191,7 @@ export function commitMenu(c: Commit, selection: Commit[] = [c]): MenuItem[] {
{ kind: "action", action: "vcs.log.interactiveRebase", arg: c, disabled: pushedCommit },
{ kind: "action", action: "vcs.log.pushUpToHere", arg: c, disabled: !canPushHere },
{ kind: "separator" },
{
kind: "action",
action: "vcs.log.rebaseOntoCommit",
arg: c,
label: tx`Rebase '${head ?? "HEAD"}' onto Selected Commit`,
disabled: !head,
},
...(branchActions.length > 2 ? [{ label: "Branches", submenu: branchActions }] : branchActions),
{ kind: "action", action: "vcs.log.newBranch", arg: c },
{ kind: "action", action: "vcs.log.newTag", arg: c },
{ kind: "separator" },
+7 -3
Переглянути файл
@@ -31,7 +31,7 @@ import { showCompareBranches } from "./CompareBranches";
import { showDiffWithWorkingTree } from "./operations";
import type { CommonBranch } from "./repoBranches";
import { runRemote, saveAll } from "./ops";
import { focusRepo, useVcs } from "./store";
import { currentRepo, focusRepo, useVcs } from "./store";
import { tx } from "@/platform/i18n";
/** `git pull <remote> <branch>` into the current branch (`origin/feat/x` → origin, feat/x). */
@@ -173,6 +173,10 @@ export function commonBranchMenu(b: CommonBranch, roots: readonly string[], done
/** `items` acting on repository `root`: it is selected (with its branches loaded) before each entry runs. */
export function inRepo(root: string, items: MenuItem[]): MenuItem[] {
const runInRepo = (run: () => unknown) => () =>
void focusRepo(root).then(() => {
if (currentRepo() === root) return run();
});
return items.map((item): MenuItem => {
if (item.kind === "separator" || item.kind === "header") return item;
if (item.kind === "action")
@@ -180,12 +184,12 @@ export function inRepo(root: string, items: MenuItem[]): MenuItem[] {
label: item.label ?? item.action,
icon: item.icon,
disabled: item.disabled,
run: () => void focusRepo(root).then(() => executeAction(item.action, item.arg)),
run: runInRepo(() => executeAction(item.action, item.arg)),
};
const run = item.run;
return {
...item,
run: run && (() => void focusRepo(root).then(run)),
run: run && runInRepo(run),
submenu: item.submenu && inRepo(root, item.submenu),
};
});
+11 -1
Переглянути файл
@@ -973,13 +973,23 @@ function loadPage(replace: boolean, id: string, before = false): Promise<void> {
} else page = await fetchPage(null);
} else page = await fetchPage(null);
}
const repoBranches = repo ? (refs[repo] ?? []) : [];
const remoteNames = repo ? repoBranches.filter((b) => b.remote).map((b) => b.name) : undefined;
const branchesByTip = new Map<string, Branch[]>();
for (const branch of repoBranches) {
if (!branch.commit) continue;
const atTip = branchesByTip.get(branch.commit);
if (atTip) atTip.push(branch);
else branchesByTip.set(branch.commit, [branch]);
}
return page.map((c) => ({
...c,
repo,
user,
userName,
readOnly: tab?.readOnly === true,
remoteNames: repo ? refs[repo]?.filter((b) => b.remote).map((b) => b.name) : undefined,
remoteNames,
refBranches: branchesByTip.get(c.id)?.filter((branch) => c.refs.includes(branch.name)),
}));
}),
);
+1
Переглянути файл
@@ -8,6 +8,7 @@ export type RepoCommit = Commit & {
user?: string | null;
userName?: string | null;
remoteNames?: string[];
refBranches?: Branch[];
readOnly?: boolean;
};
export const commitRepo = (c: Commit | undefined): string | null | undefined => (c as RepoCommit | undefined)?.repo;
+2 -1
Переглянути файл
@@ -57,5 +57,6 @@
"Recommended": "Recommended",
"No preview": "No preview",
"Running in the background": "Running in the background",
"Couldn't stop the background task": "Couldn't stop the background task"
"Couldn't stop the background task": "Couldn't stop the background task",
"Branch '{name}'": "Branch '{name}'"
}
+1
Переглянути файл
@@ -4269,6 +4269,7 @@
"Branch {name}": "分支 {name}",
"Tag {name}": "标签 {name}",
"Branch {branch} of {repository}": "{repository} 的分支 {branch}",
"Branch '{name}'": "分支 '{name}'",
"Branches of {root}": "{root} 的分支",
"Include {name} in commit": "在提交中包含 {name}",
"Compare {current} with {branch}": "比较 {current} 与 {branch}",