{"record":{"id":"709222de52a438fa","repo":"gitbutlerapp/gitbutler","slug":"only-local-branches-under-refs-heads-are-supported","errorCode":null,"errorMessage":"Only local branches under refs/heads/ are supported","messagePattern":"Only local branches under refs/heads/ are supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/branch/update.rs","lineNumber":160,"sourceCode":"        Some(Category::LocalBranch) => Ok(reference.name),\n        Some(Category::RemoteBranch) => {\n            bail!(\n                \"Expected a local branch, but '{}' is a remote-tracking branch\",\n                reference.name.shorten()\n            )\n        }\n        _ => bail!(\n            \"Expected a local branch, but '{}' is not under refs/heads/\",\n            reference.name.shorten()\n        ),\n    }\n}\n\nfn normalize_local_branch_ref(branch: &str) -> anyhow::Result<FullName> {\n    let full = if branch.starts_with(\"refs/heads/\") {\n        branch.to_owned()\n    } else if branch.starts_with(\"refs/\") {\n        bail!(\"Only local branches under refs/heads/ are supported\");\n    } else {\n        format!(\"refs/heads/{branch}\")\n    };\n    FullName::try_from(full).map_err(|err| anyhow::anyhow!(\"Invalid branch name: {err}\"))\n}\n\nfn output_apply_result(\n    branch_ref: &FullNameRef,\n    divergence: &but_workspace::branch::IntegrationDivergenceDisplay,\n    dry_run: bool,\n    verbose: bool,\n    result: IntegrateBranchResult,\n    out: &mut OutputChannel,\n) -> anyhow::Result<()> {\n    if let Some(out) = out.for_human() {\n        if dry_run {\n            write!(\n                out,","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but/src/command/branch/update.rs#L142-L178","documentation":"normalize_local_branch_ref only accepts bare branch names or full refs under refs/heads/. A ref under refs/ but outside refs/heads/ (e.g. refs/remotes/..., refs/tags/...) cannot denote a local branch, so it is rejected early.","triggerScenarios":"Calling `but branch update` with an argument starting with `refs/` but not `refs/heads/`, such as `refs/remotes/origin/main` or `refs/tags/v1.0`.","commonSituations":"Copy-pasting full ref names from git tooling output; scripts built around remote-tracking refs; passing tags by full ref path.","solutions":["Use the bare local branch name (e.g. `main`) instead of a full ref under refs/remotes or refs/tags.","If you must pass a full ref, ensure it starts with refs/heads/.","Strip the remote prefix and create a local tracking branch if needed."],"exampleFix":"// before\nbut branch update refs/remotes/origin/main --to abc123\n// after\nbut branch update main --to abc123","handlingStrategy":"validation","validationCode":"if (ref.startsWith('refs/') && !ref.startsWith('refs/heads/')) {\n  throw new Error(`Only refs under refs/heads/ are accepted; got '${ref}'`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass bare branch names rather than full ref paths.","Normalize any tooling-supplied refs to refs/heads/<name> or the short name.","Handle remote-tracking and tag refs separately in scripts before calling but."],"tags":["git","branch","ref-format","cli"],"backgroundTag":"invalid-argument-format","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"}