gitbutlerapp/gitbutler · error

Cannot merge : it shares no history with /

Error message

Cannot merge {branch_name}: it shares no history with {fetch_remote_name}/{target_branch_name}

What it means

Landing a branch merges it into the remote target branch. Git cannot merge two unrelated histories (no common merge-base ancestor). Rather than producing a broken merge, `decide_land_outcome` refuses with this error.

Solutions

  1. Rebase the branch onto the target to establish common history, or cherry-pick its commits onto a branch created from the target
  2. Recreate the branch from the current target branch (`git switch -c fix origin/main`) and reapply changes
  3. Verify you are merging into the intended target branch — pointing at the wrong remote branch can look like unrelated history

Example fix

# before
but merge orphan-branch
# error: shares no history with origin/main

# after
git switch -c orphan-branch-rebased origin/main
git cherry-pick <commits-from-orphan-branch>
but merge orphan-branch-rebased
Defensive patterns

Strategy: validation

Validate before calling

let base = repo.merge_base(feature_oid, target_oid);
if base.is_err() {
    println!("branch shares no history with target; rebase or recreate branch");
    return Ok(());
}

Try / catch

match land_result {
    Err(e) if e.to_string().contains("shares no history") => {
        recreate_branch_from_target();
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `but merge <branch>` where the feature branch and `{fetch_remote}/{target_branch}` share no merge-base — typically when the branch was created from an orphan/unrelated history or the target was re-created from scratch.

Common situations: Target branch force-recreated without history; branch created in a fresh repo with no shared root; repo seeded from unrelated template histories.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

    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 {
        return Ok(LandOutcome::AlreadyIntegrated);
    }
    if merge_base == target_oid && !no_ff {
        return Ok(LandOutcome::FastForward {
            feature_oid,
            target_oid,
        });
    }

    // Diverged (or `--no-ff`): build a real merge commit. Use GitButler's canonical tree-merge
    // options (rename tracking on, fail-fast) so a rename+edit can't silently mismerge, and sign
    // the commit per config so it survives signed-branch protection on the target.
    // Use each commit's resolved tree as its side of the 3-way merge. For an ordinary

View on GitHub (pinned to 58e5313667)