fix(git): the branch switcher lists and checks out branches only the remote has

GET /api/lanes/:id/git/branches read only refs/heads, so a branch someone
else pushed never showed after a fetch or pull, and `switch` refused it
(ENOBRANCH). It now also returns `remotes`: fetched remote-tracking branches
with no local branch of that name (origin/HEAD left out), listed under
"On the remote"; switching to one runs `git switch -c <b> --track
refs/remotes/<remote>/<b>` with the remote ref looked up, never passed
through (bare name only when exactly one remote has it, else EAMBIGUOUS).
The bar also re-reads the branch list after a fetch or pull instead of
keeping the list it loaded first.
This commit is contained in:
2026-10-28 14:57:32 +07:00
parent fa27b299e7
commit 14e979837e
14 changed files with 197 additions and 24 deletions
+8 -3
View File
@@ -48,6 +48,7 @@ const {
isGitRepo,
isValidBranchName,
listBranches,
listRemoteBranches,
listWorktrees,
resetWorktree,
resolveBase,
@@ -1913,7 +1914,9 @@ router.get("/:id/git/tree", async (req, res) => {
});
/**
* The lane's own local branches, for the branch switcher. Separate from
* The lane's own local branches, for the branch switcher, plus `remotes`: the
* fetched remote-tracking branches with no local branch yet (`origin/feature`
* — switching to one creates its tracking branch). Separate from
* `GET /branches` (which takes a candidate repo PATH from the query, for a
* lane that does not exist yet); this one resolves the repo from the lane row,
* so no path ever comes from the request.
@@ -1925,9 +1928,10 @@ router.get("/:id/git/branches", async (req, res) => {
try {
const { branches, current } = await listBranches(cwd);
const worktrees = await listWorktrees(cwd).catch(() => []);
res.json({ available: true, branches, current, worktrees });
const remotes = (await listRemoteBranches(cwd).catch(() => [])).map((r) => r.name);
res.json({ available: true, branches, remotes, current, worktrees });
} catch {
res.json({ available: false, branches: [], current: null, worktrees: [] });
res.json({ available: false, branches: [], remotes: [], current: null, worktrees: [] });
}
});
@@ -1987,6 +1991,7 @@ router.post("/:id/git/:action", sameOriginGuard, async (req, res) => {
"EBADMESSAGE",
"EBADBRANCH",
"ENOBRANCH",
"EAMBIGUOUS",
"EBRANCHEXISTS",
"EBRANCHBUSY",
"EDIRTY",