gitbutlerapp/gitbutler · error · anyhow::Error

Worktree {name} has a workspace ref checked out, so there is

Error message

Worktree {name} has a workspace ref checked out, so there is no branch to commit to

What it means

worktree_branch() resolves which branch a worktree's HEAD is on before an operation may commit to it. Besides detached HEAD, it explicitly refuses GitButler workspace refs (but_core::is_workspace_ref_name): such worktrees render without a heading but their HEAD points at internal workspace state, and a commit meant for a branch must never land on the workspace ref. The checkout can change between TUI render and confirm, so this is re-checked at confirm time.

Source

Thrown at crates/but/src/utils/worktrees.rs:19

use anyhow::Context as _;
use bstr::BStr;

/// The branch checked out in the linked worktree `name`, which is where a commit made from that
/// checkout goes and where a commit moved onto its lane lands.
///
/// A detached worktree has no branch to move, so it is refused rather than silently targeting
/// somewhere else. The same goes for a workspace ref: such worktrees never render a heading,
/// but the checkout can change between render and confirm, and a workspace ref must never
/// receive a commit meant for a branch.
pub(crate) fn worktree_branch(
    repo: &gix::Repository,
    name: &BStr,
) -> anyhow::Result<gix::refs::FullName> {
    let worktree_repo = but_workspace::worktrees::open_worktree_repo(repo, name)?;
    let branch = worktree_repo.head_name()?.with_context(|| {
        format!("Worktree {name} has a detached HEAD, so there is no branch to commit to")
    })?;
    anyhow::ensure!(
        !but_core::is_workspace_ref_name(branch.as_ref()),
        "Worktree {name} has a workspace ref checked out, so there is no branch to commit to"
    );
    Ok(branch)
}

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Refresh/re-render the TUI, reselect the target, and confirm again
  2. In the affected worktree, put HEAD back on a real branch: `git switch <branch>`
  3. Run only one GitButler surface (app or CLI) per repository at a time
Defensive patterns

Strategy: validation

Validate before calling

let head = worktree_repo.head_name()?;
match head {
    Some(name) if !but_core::is_workspace_ref_name(name.as_ref()) => Ok(name),
    Some(_) => anyhow::bail!("workspace ref checked out; reselect after refresh"),
    None => anyhow::bail!("detached HEAD; no branch"),
}

Try / catch

On this error, re-read the worktree's HEAD and restart from a fresh render; never retry the commit against the workspace-ref state.

Prevention

When it happens

Trigger: Confirming an operation that targets a worktree (commit, branch move) after that worktree's HEAD was switched to a GitButler workspace ref, by a re-render in the TUI or by another but/GitButler process touching the worktree concurrently.

Common situations: Race between TUI render and confirmation; running the but CLI/TUI and the GitButler desktop app against the same repository at the same time.

Related errors


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