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:
+26
-1
@@ -55,6 +55,7 @@ const {
|
||||
git: rawGit,
|
||||
isValidBranchName,
|
||||
listBranches,
|
||||
listRemoteBranches,
|
||||
branchCheckedOutAt,
|
||||
statusCounts,
|
||||
operationInProgress,
|
||||
@@ -532,7 +533,31 @@ async function runGitAction(dir, action, body = {}) {
|
||||
if (exists) throw bad("EBRANCHEXISTS", `branch ${branch} already exists`);
|
||||
return done(action, await git(dir, ["switch", "-c", branch]), branch);
|
||||
}
|
||||
if (!exists) throw bad("ENOBRANCH", `branch ${branch} does not exist locally`);
|
||||
if (!exists) {
|
||||
// A branch only a remote has (fetched, never checked out here): its local
|
||||
// tracking branch is created and switched to. Named either as the remote
|
||||
// ref (`origin/feature`) or bare (`feature`, when exactly one remote has
|
||||
// it). The remote ref is looked up among the fetched ones, never passed
|
||||
// through from the request.
|
||||
const remote = (await listRemoteBranches(dir)).filter(
|
||||
(r) => r.name === branch || r.branch === branch
|
||||
);
|
||||
const pick = remote.find((r) => r.name === branch) || (remote.length === 1 ? remote[0] : null);
|
||||
if (!pick) {
|
||||
if (remote.length > 1) {
|
||||
throw bad(
|
||||
"EAMBIGUOUS",
|
||||
`branch ${branch} is on several remotes (${remote.map((r) => r.name).join(", ")}): pick one`
|
||||
);
|
||||
}
|
||||
throw bad("ENOBRANCH", `branch ${branch} does not exist locally or on a remote`);
|
||||
}
|
||||
return done(
|
||||
action,
|
||||
await git(dir, ["switch", "-c", pick.branch, "--track", `refs/remotes/${pick.name}`]),
|
||||
pick.branch
|
||||
);
|
||||
}
|
||||
const busyAt = await branchCheckedOutAt(dir, branch);
|
||||
if (busyAt) throw bad("EBRANCHBUSY", `branch ${branch} is checked out at ${busyAt}`);
|
||||
return done(action, await git(dir, ["switch", branch]), branch);
|
||||
|
||||
Reference in New Issue
Block a user