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
- Rebase the branch onto the target to establish common history, or cherry-pick its commits onto a branch created from the target
- Recreate the branch from the current target branch (`git switch -c fix origin/main`) and reapply changes
- 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
- Create branches from the current target branch, never from orphan roots
- Avoid force-recreating the target branch from scratch without migrating history
- Verify the target remote/branch name resolves to the intended upstream before landing
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
- An octopus merge commits must have at least two parents
- Branch not found
- `but merge` does not yet support triangular remotes
- cannot currently handle more than 1 parent
- Cannot merge : merging into / resulted in conflicts. Rebase…
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 ordinaryView on GitHub (pinned to 58e5313667)