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 the workspace cannot be empty

What it means

In an ad-hoc workspace, unapplying the very branch that the workspace ref points at (the entrypoint branch) would leave the workspace with nothing in it, which ad-hoc workspaces cannot represent. The guard compares the branch to unapply against the workspace's own ref name and refuses the identity case. Unapply any other branch, or dissolve the workspace via the workspace-reference path.

Source

Thrown at crates/but-workspace/src/branch/unapply.rs:217

        let branch_commit_id = branch_ref
            .as_mut()
            .map(|reference| reference.peel_to_id().map(|id| id.detach()))
            .transpose()?;

        if ws.has_workspace_commit_in_ancestry(repo) {
            bail!("Refusing to work on workspace whose workspace commit isn't at the top");
        }

        let workspace_ref_name = ws.ref_name().map(ToOwned::to_owned);
        if matches!(ws.kind, but_graph::workspace::WorkspaceKind::AdHoc)
            && branch_ref
                .as_ref()
                .zip(workspace_ref_name.as_ref())
                .is_some_and(|(to_unapply, workspace_ref_name)| {
                    to_unapply.name() == workspace_ref_name.as_ref()
                })
        {
            bail!(
                "Cannot unapply branch '{branch}' from an ad-hoc workspace because the workspace cannot be empty",
                branch = branch.shorten()
            );
        }

        if let Some(workspace_ref_name) = workspace_ref_name.as_ref()
            && workspace_ref_name.as_ref() == branch
        {
            return unapply_workspace_reference(
                ws,
                repo,
                meta,
                workspace_ref_name.as_ref(),
                workspace_disposition,
            );
        }

        let branch_in_ws = ws.find_segment_and_stack_by_refname(branch);

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Unapply a different branch; the entrypoint branch of an ad-hoc workspace cannot be removed by unapply.
  2. To empty the workspace, switch away from it / dissolve it through the workspace-unapply flow instead.
  3. Exclude the workspace ref name from any batch-unapply loops.

Example fix

// before
for branch in applied_branches { unapply(repo, meta, &ws, branch, opts)?; }

// after
for branch in applied_branches {
    if ws.ref_name().is_some_and(|ws_ref| ws_ref == branch) { continue; }
    unapply(repo, meta, &ws, branch, opts)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if matches!(ws.kind, but_graph::workspace::WorkspaceKind::AdHoc)
    && ws.ref_name().is_some_and(|ws_ref| ws_ref == branch)
{
    // the workspace's own branch cannot be unapplied in ad-hoc mode
    return show_notice("unapply a different branch or dissolve the workspace");
}

Type guard

fn is_workspace_entrypoint_branch(ws: &but_graph::Workspace, branch: &FullNameRef) -> bool {
    matches!(ws.kind, but_graph::workspace::WorkspaceKind::AdHoc)
        && ws.ref_name().is_some_and(|r| r == branch)
}

Try / catch

match unapply(repo, meta, &ws, branch, opts) {
    Err(err) if err.to_string().contains("workspace cannot be empty") => {
        ui::info("Switch away from the workspace to remove it");
        Ok(default_outcome())
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling unapply(branch) in an ad-hoc workspace where branch == ws.ref_name() — i.e., trying to unapply the checked-out entrypoint branch itself.

Common situations: UI 'remove' button wired to unapply on the workspace's own branch; scripts that iterate all applied branches including the entrypoint one.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/6346b694659912b9. Report an issue: GitHub.