gitbutlerapp/gitbutler · error

Branch not found

Error message

Branch {branch_name} not found

What it means

`decide_land_outcome` resolves the feature branch by constructing `refs/heads/{branch_name}` and peeling it to an OID. If the repository contains no such reference, it throws "Branch {branch_name} not found". This is a pre-flight lookup in the land/merge path: without the feature ref's OID the merge-base/merge analysis cannot proceed.

Solutions

  1. Check the branch exists locally: `git branch --list <branch_name>`; create or fetch it if missing.
  2. Use the exact current branch name from workspace/stack metadata instead of a cached one.
  3. If the branch was already merged and deleted, skip landing — the outcome is already achieved.
  4. Verify you are operating on the correct repository/workdir.

Example fix

// before
land_branch("feature-x", ...); // may not exist
// after
if !repo.try_find_reference(&format!("refs/heads/feature-x"))?.is_some() {
    eprintln!("feature-x not found locally; fetching or skipping");
    return Ok(());
}
land_branch("feature-x", ...);
Defensive patterns

Strategy: validation

Validate before calling

// check the feature branch ref exists before landing
if repo.try_find_reference(&format!("refs/heads/{branch_name}"))?.is_none() {
    return Err(anyhow::anyhow!("branch {branch_name} does not exist locally"));
}

Try / catch

match land_outcome(branch) {
    Err(e) if e.to_string().contains("not found") =>
        eprintln!("branch {branch} missing locally; fetch first or skip"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling the land/merge API with a `branch_name` that has no `refs/heads/<name>` reference in the repo — typically after the branch was deleted, never created, renamed, or when passing a branch that lives only in the virtual (GitButler-applied) workspace rather than as a real git branch.

Common situations: Landing a branch that was already merged and deleted; a typo'd or stale branch name in automation; running the operation on a clone that lacks the local branch; GitButler workspace stacks whose heads are not checked out as plain branches.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/ec544f17a5f7f468. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-api/src/land/merge.rs:39

    Merge {
        oid: gix::ObjectId,
        target_oid: gix::ObjectId,
    },
}

/// Decide how to land `branch_name` onto the target and, for the merge case, build a signed,
/// rename-aware merge commit. Conflicts bail here, before anything is pushed or moved.
pub(super) fn decide_land_outcome(
    repo: &gix::Repository,
    branch_name: &str,
    fetch_remote_name: &str,
    target_branch_name: &str,
    no_ff: bool,
) -> anyhow::Result<LandOutcome> {
    let feature_ref_name = format!("refs/heads/{branch_name}");
    let feature_oid = repo
        .try_find_reference(&feature_ref_name)?
        .ok_or_else(|| anyhow::anyhow!("Branch {branch_name} not found"))?
        .into_fully_peeled_id()?
        .detach();

    let target_ref_name = format!("refs/remotes/{fetch_remote_name}/{target_branch_name}");
    let target_oid = repo
        .try_find_reference(&target_ref_name)?
        .ok_or_else(|| anyhow::anyhow!("Target branch {target_ref_name} not found"))?
        .into_fully_peeled_id()?
        .detach();

    // No common ancestor: refuse rather than merge two unrelated histories onto the target.
    let Some(merge_base) = super::merge_base_opt(repo, feature_oid, target_oid)? else {
        bail!(
            "Cannot merge {branch_name}: it shares no history with {fetch_remote_name}/{target_branch_name}"
        );
    };

    if merge_base == feature_oid {

View on GitHub (pinned to 58e5313667)