gitbutlerapp/gitbutler · error · anyhow::Error

Branch name '{}' collides with existing branch '{}'

Error message

Branch name '{}' collides with existing branch '{}'

What it means

Git refused to create the ref because its name conflicts with an existing ref in the same namespace: you cannot have both refs/heads/foo and refs/heads/foo/bar in a files-based ref store (a ref is both a file path and a directory). gix reports this as a not-a-directory edit error; the code remaps it to a friendly message naming the colliding existing ref.

Source

Thrown at crates/but-workspace/src/branch/create_reference.rs:504

                 belongs to another branch in the workspace. Each commit can only \
                 belong to one branch at a time.",
                ref_name.shorten(),
                ref_target_id,
            )
        }

        // Actually apply the changes
        repo.reference(
            ref_name,
            ref_target_id,
            PreviousValue::ExistingMustMatch(gix::refs::Target::Object(ref_target_id)),
            "Dependent branch by GitButler",
        )
        .map_err(|err| {
            if is_not_a_directory_ref_edit_error(&err)
                && let Ok(Some(colliding_ref)) = find_colliding_ref_ancestor(repo, ref_name)
            {
                return anyhow::anyhow!(
                    "Branch name '{}' collides with existing branch '{}'",
                    ref_name.shorten(),
                    colliding_ref.shorten()
                );
            }
            let code = match err {
                gix::reference::edit::Error::FileTransactionCommit(
                    gix::refs::file::transaction::commit::Error::CreateOrUpdateRefLog(
                        gix::refs::file::log::create_or_update::Error::MissingCommitter,
                    ),
                ) => Some(but_error::Code::AuthorMissing),
                _ => None,
            };
            let err = anyhow::Error::from(err);
            if let Some(code) = code {
                err.context(code)
            } else {
                err

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Rename the new branch so neither name is a path-prefix of the other (e.g. feature-x instead of feature/x)
  2. Delete or rename the colliding existing branch named in the error if it is obsolete
  3. When generating names programmatically, check the existing ref set for both prefix and extension collisions first

Example fix

# before
git branch feature        # exists
# creating feature/x → "Branch name 'feature/x' collides with existing branch 'feature'"
# after — use a non-hierarchical name
git branch feature-x      # no collision
Defensive patterns

Strategy: validation

Validate before calling

// before creating refs, check both collision directions against existing refs
fn collides(repo: &gix::Repository, name: &gix::refs::FullName) -> Option<gix::refs::FullName> {
    let names: Vec<_> = repo.references().ok()?.map_while(Result::ok)
        .map(|r| r.name().to_owned()).collect();
    names.into_iter().find(|existing|
        existing.as_bstr() == name.as_bstr()
        || existing.as_bstr().starts_with(format!("{}/", name.as_bstr()).as_bytes())
        || name.as_bstr().starts_with(format!("{}/", existing.as_bstr()).as_bytes()))
}

Type guard

fn is_safe_branch_name(existing: &[String], candidate: &str) -> bool {
    existing.iter().all(|e| e != candidate && !e.starts_with(&format!("{candidate}/")) && !candidate.starts_with(&format!("{e}/")))
}

Try / catch

match create_reference(...) {
    Err(e) if e.to_string().contains("collides with existing branch") => { /* extract colliding name, suggest alternative like replacing '/' with '-' */ }
    r => r,
}

Prevention

When it happens

Trigger: Creating dependent branch 'feature/x' when branch 'feature' already exists (or vice versa) via create_reference; any generated branch name whose path prefix equals an existing ref, or that extends an existing ref with a slash component.

Common situations: Automatic branch-name generation (e.g. stacking schemes that insert slashes) colliding with user-created branches; importing branches from another remote with hierarchical naming.

Related errors


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