{"record":{"id":"a54299fb6ddd7f2b","repo":"gitbutlerapp/gitbutler","slug":"branch-already-exists","errorCode":null,"errorMessage":"Branch '{}' already exists","messagePattern":"Branch '(.+?)' already exists","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-api/src/branch.rs","lineNumber":1587,"sourceCode":"    branch_checkout_new_with_perm(ctx, name, guard.write_permission())\n}\n\n/// Creates a new local branch at the project target SHA and checks it out under\n/// caller-held exclusive repository access.\npub fn branch_checkout_new_with_perm(\n    ctx: &mut but_ctx::Context,\n    name: Option<String>,\n    perm: &mut RepoExclusive,\n) -> anyhow::Result<BranchCheckoutResult> {\n    let target_commit_id = ctx.project_meta()?.target_commit_id_or_err()?;\n    let branch = {\n        let repo = ctx.repo.get()?;\n        let branch = match name {\n            Some(name) => {\n                let normalized = but_core::branch::normalize_short_name(name.as_str())?;\n                let branch = gix::refs::Category::LocalBranch.to_full_name(normalized.as_bstr())?;\n                if repo.try_find_reference(branch.as_ref())?.is_some() {\n                    bail!(\"Branch '{}' already exists\", branch.as_bstr());\n                }\n                branch\n            }\n            None => unique_canned_refname(&repo)?,\n        };\n\n        repo.reference(\n            branch.as_ref(),\n            target_commit_id,\n            PreviousValue::MustNotExist,\n            \"branch checkout new\",\n        )\n        .with_context(|| format!(\"Could not create branch '{}'\", branch.as_bstr()))?;\n        branch\n    };\n\n    branch_checkout_with_perm_only(ctx, branch, perm)\n}","sourceCodeStart":1569,"sourceCodeEnd":1605,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-api/src/branch.rs#L1569-L1605","documentation":"Thrown when creating a branch with an explicitly requested name: after normalizing the short name and expanding it to a full `refs/heads/...` name, the reference already exists in the repository, so creation would silently overwrite or conflict. The existing full refname is included in the message.","triggerScenarios":"Calling the create-branch API with `name` set to a branch that already resolves via `repo.try_find_reference` — same-name branch exists locally, or the normalized name collides with an existing ref.","commonSituations":"Re-running a script that creates branches without idempotency; case-insensitive filesystem collisions between differently-cased names; UI retry after a partially-completed create; normalization making `feature/x` collide with an existing ref.","solutions":["Pick a different branch name or check existence first before calling create","Use the no-name variant of the API, which generates a unique canned refname automatically","If the existing branch is stale and safe to drop, delete it first, then create","Check the exact name in the message — normalization may have altered your input"],"exampleFix":"// before\nawait api.createBranch({ name: \"feature\" }); // bails if refs/heads/feature exists\n// after\nif (!(await api.branchExists(\"feature\"))) {\n  await api.createBranch({ name: \"feature\" });\n} else {\n  await api.createBranch({}); // unique canned name\n}","handlingStrategy":"validation","validationCode":"const full = `refs/heads/${name}`;\nif (await api.refExists(full)) throw new Error(`branch ${full} already exists`);","typeGuard":"function canCreateBranch(name: string, existing: string[]): boolean {\n  return !existing.map(b => b.replace(\"refs/heads/\", \"\")).includes(name);\n}","tryCatchPattern":"try {\n  await api.createBranch({ name });\n} catch (e) {\n  if (String(e).includes(\"already exists\")) {\n    await api.createBranch({}); // fall back to unique canned name\n  } else { throw e; }\n}","preventionTips":["Check ref existence before creating a named branch","Make create scripts idempotent (create-or-skip)","Omit the name to let the API generate a unique canned refname","Beware case-insensitive filesystems when choosing names"],"tags":["git","branch","conflict","already-exists"],"backgroundTag":"file-already-exists","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}