GitoxideLabs/gitoxide · error

cannot delete because another worktree has it checked out

Error message

cannot delete {} because another worktree has it checked out

What it means

During branch cleanup after a rebase, a rewritten branch that is planned for deletion (`expected.new.is_none()`) is found checked out in a different worktree. Deleting a branch referenced by another worktree's HEAD is not allowed, so the operation bails naming the branch via `expected.name.shorten()`. If it's checked out in the *same* repo/git-dir it is silently skipped (`continue`).

Solutions

  1. Remove the other worktree (`git worktree remove <path>`) or switch its HEAD off the branch, then retry.
  2. Detach the other worktree's HEAD so the branch is no longer checked out there.
  3. Skip deletion for that branch: keep the old branch instead of planning `new: None` for it.
  4. Run the rebase from (or after consolidating) the worktree that actually owns the branch.

Example fix

// before
worktree::remove(repo, other_path)?; // branch still checked out -> bail
// after
detach_head_or_switch(other_worktree, "main")?; // release the branch
worktree::remove(repo, other_path)?;
edit.rebase(...)?; // deletion now succeeds
Defensive patterns

Strategy: validation

Validate before calling

for wt in repo.worktrees()? {
    let wt_repo = wt.into_repo()?;
    if wt_repo.git_dir() != repo.git_dir()
        && let Some(head_ref) = wt_repo.head()?.referent_name()
        && branches_planned_for_deletion.contains(&head_ref.to_owned()) {
        // detach or remove this worktree first
    }
}

Prevention

When it happens

Trigger: Running a rebase edit that rewrites and deletes branches while a separate linked worktree has `HEAD` pointed at one of the to-be-deleted old branch names — i.e. `worktree_repo.git_dir() != repo.git_dir()` and the planned new branch is `None`.

Common situations: Multi-worktree setups where an old feature branch checked out in a second worktree gets rewritten/deleted by a rebase run from the main worktree; CI or scripts operating on the same repository from multiple worktrees.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/332d0579394cc939. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/edit/rebase.rs:2913

    for worktree_repo in repos {
        if !seen.insert(worktree_repo.git_dir().to_owned()) {
            continue;
        }
        let Ok(head) = worktree_repo.head() else {
            continue;
        };
        let Some(old) = head.id().map(gix::Id::detach) else {
            continue;
        };
        let planned = head.referent_name().and_then(|name| {
            expected_refs.and_then(|refs| refs.iter().find(|expected| expected.name.as_bstr() == name.as_bstr()))
        });
        let new = match planned {
            Some(expected) if expected.new.is_none() => {
                if worktree_repo.git_dir() == repo.git_dir() {
                    continue;
                }
                anyhow::bail!(
                    "cannot delete {} because another worktree has it checked out",
                    expected.name.shorten()
                );
            }
            Some(expected) => Some(expected.new),
            None => rewritten.get(&old).copied(),
        };
        let Some(new) = new else { continue };
        if worktree_repo.workdir().is_none() && worktree_repo.is_bare() {
            continue;
        }
        let old_tree = worktree_repo.find_commit(old)?.tree_id()?.detach();
        let new_tree = match new {
            Some(new) => repo.find_commit(new)?.tree_id()?.detach(),
            None if worktree_repo.head()?.referent_name().is_some() => repo.empty_tree().id,
            None => anyhow::bail!("a detached checked-out root commit cannot be removed"),
        };
        if old_tree == new_tree {

View on GitHub (pinned to e73179060b)