gitbutlerapp/gitbutler · error

Branch {branch_name} not found

Error message

Branch {branch_name} not found

What it means

branch_land resolves refs/heads/<branch_name> in the local repository via gix try_find_reference; if no such local branch exists it bails with this message before fetching or mutating anything. It looks for a real local ref — remote-only names, virtual names, and typos all fail here.

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 land {branch_name}: it shares no history with {fetch_remote_name}/{target_branch_name}"
        );
    };

    if merge_base == feature_oid {

View on GitHub (pinned to 2497b8007a)

Solutions

  1. List candidates first: git branch --list (or the workspace stack listing) and land the exact local branch name.
  2. If the branch exists only on the remote, materialize the local ref first: git fetch <remote> && git branch <name> <remote>/<name>.
  3. Strip remote prefixes — pass the short name, not origin/<name>.

Example fix

git branch --list 'feat/*'
git branch feat/auth origin/feat/auth   # only if the local ref is missing
but land feat/auth
Defensive patterns

Strategy: validation

Validate before calling

fn local_branch_exists(repo: &gix::Repository, branch: &str) -> anyhow::Result<bool> {
    Ok(repo.try_find_reference(&format!("refs/heads/{branch}"))?.is_some())
}

Prevention

When it happens

Trigger: `but land <name>` (branch_land -> decide_land_outcome) where refs/heads/<name> does not exist: typo, name written as origin/<name>, branch that exists only on the remote, or a local branch deleted/pruned earlier.

Common situations: Tab-completing remote branch names; landing after branch cleanup pruned the local ref; case-sensitivity mistakes; scripts forwarding reflogs or remote names.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/ec544f17a5f7f468. Report an issue: GitHub.