feat(git): history graph with search, commit details, file history, blame/browse at a revision, compare refs, and multi-commit cherry-pick/revert with preview, pause banner and undo

This commit is contained in:
2026-11-02 12:06:39 +07:00
parent 2b5d7268ed
commit e1f433804c
35 changed files with 6277 additions and 319 deletions
+19
View File
@@ -30,6 +30,11 @@
* same clean-tree/repo-root guards, same conflict flow, and `merge-commit`/
* `merge-abort` finish or abort whichever of the three git has open.
*
* Several commits at once (`shas`), a paused pick's `pick-continue` /
* `pick-skip` / `pick-abort`, and `undo-pick` (a soft reset back over what
* a pick just made) live in git-pick.js, dispatched at the top of
* `runGitAction` under the same guards.
*
* `undo-commit` (`reset --soft HEAD~1`) and `amend` rewrite the last commit,
* so both refuse once any remote-tracking branch holds it (EPUSHED): an
* unpushed commit is the only one whose rewrite costs nobody else anything.
@@ -116,6 +121,11 @@ const ACTIONS = new Set([
"shelve",
"unshelve",
"shelf-drop",
// git-pick.js: a paused cherry-pick/revert's banner, and taking a pick back.
"pick-continue",
"pick-skip",
"pick-abort",
"undo-pick",
]);
// Branch & tag tools (rename, upstream, tag create/delete/push): git-refs.js.
@@ -384,6 +394,15 @@ async function runGitAction(dir, action, body = {}, opts = {}) {
if (gitRefs.handles(action, body)) {
return gitRefs.refsAction(dir, action, body, { networkGit, PROTECTED });
}
// Several commits (`shas`), and the paused sequence's own buttons: git-pick.js,
// which keeps every guard below. A single `sha` stays on the path further down.
const pick = require("./git-pick");
if (
pick.PICK_ACTIONS.has(action) ||
((action === "cherry-pick" || action === "revert") && Array.isArray(body.shas))
) {
return pick.runPickAction(dir, action, body);
}
if (BLOCKED_WHILE_MERGING.has(action)) {
const open = await operationInProgress(dir);
if (open) throw bad("EMERGING", `a ${open} is in progress: finish or abort it first`);