gitbutlerapp/gitbutler · error
Cannot unapply branch '{branch}' from an ad-hoc workspace be
Error message
Cannot unapply branch '{branch}' from an ad-hoc workspace because non-tip branches can only disappear if their now removed metadata disambiguated them What it means
After removing the branch's metadata, unapply re-runs the traversal with an empty overlay to see whether the branch really disappears from the workspace. If it still resolves as a segment, the branch is not the tip of its own history — other refs make it visible — and removing only its metadata cannot make it vanish. The operation aborts rather than leave a half-removed state.
Source
Thrown at crates/but-workspace/src/branch/unapply.rs:270
bail!("Cannot unapply a branch from an ad-hoc detached workspace");
};
let mut ws_md = meta.workspace(workspace_ref_name.as_ref())?;
if ws.kind.has_managed_ref() || ws.has_metadata() {
ws.reconcile_metadata(&mut ws_md)?;
}
let branch_removed_from_ws_meta = ws_md.unapply_branch(branch);
if !branch_removed_from_ws_meta {
// The branch wasn't in workspace metadata, yet it was present, so also delete its branch metadata
// as it could be used to disambiguate the segment.
// TODO: this will actually be observable even if it doens't work, unless it's run in a transaction, which right now it's not!
// Should be able to redo the traversal with an overlay that hides branch metadata, but I'd say it's not important enough.
meta.remove(branch)?;
let graph = ws
.graph
.redo_traversal_with_overlay(repo, meta, Overlay::default())?;
let workspace = graph.into_workspace()?;
if workspace.refname_is_segment(branch) {
bail!(
"Cannot unapply branch '{branch}' from an ad-hoc workspace because non-tip branches can only disappear if their now removed metadata disambiguated them",
branch = branch.shorten()
);
}
return Ok(Outcome::new(Cow::Owned(workspace)));
}
// Everything past this point is stricly in non-dry-run mode and we may totally end up in intermediate states
// if something fails.
// Redo the traversal with the changed workspace metadata so code below can rely on the reconciled version.
let ws = ws
.graph
.redo_traversal_with_overlay(
repo,
meta,
Overlay::default()
.with_dropped_references([branch.to_owned()])
.with_workspace_metadata_override(Some((View on GitHub (pinned to caf1f223d3)
Solutions
- Unapply branches top-down (tip first) so each removal actually detaches the segment.
- Delete or move the other refs that keep the branch visible (e.g. the branch's own git ref) before unapplying.
- Use the workspace unapply flow, which handles ref and metadata disposal together.
Defensive patterns
Strategy: validation
Validate before calling
// before unapplying, verify the branch would disappear once its metadata is dropped
let graph = ws.graph.redo_traversal_with_overlay(repo, meta, Overlay::default())?;
let check = graph.into_workspace()?;
if !check.refname_is_segment(branch) || check.refname_is_segment(branch) {
// cheap pre-check: only attempt when the branch owns its tip
}
// simplest reliable guard: unapply stacks top-down (tip branches first) Try / catch
match unapply(repo, meta, &ws, branch, opts) {
Err(err) if err.to_string().contains("non-tip branches can only disappear") => {
ui::info("Unapply the branch above this one first");
Ok(default_outcome())
}
other => other,
} Prevention
- Always unapply stacked branches top-down, tip first.
- For lower stacked branches, delete their git ref as part of the operation.
- Surface stack order in the UI so users unapply in a valid sequence.
When it happens
Trigger: Unapplying a branch in an ad-hoc workspace where the branch is non-tip: it is still reachable/visible through other refs or segments after its disambiguating metadata is gone.
Common situations: Stacked branches sharing history where the lower branch ref still points into the stack; workspaces where the branch was only projected thanks to metadata that has now been removed.
Related errors
- Cannot reorder '{subject_branch_name}' in single-branch mode
- Refusing to work on workspace whose workspace commit isn't a
- Cannot unapply branch '{branch}' from an ad-hoc workspace be
- Cannot unapply non-existing branch '{branch}'
- Cannot unapply a branch from an ad-hoc detached workspace
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/8ac40657f282e981.
Report an issue: GitHub.