{"record":{"id":"cbfc09124feca2f7","repo":"gitbutlerapp/gitbutler","slug":"no-merge-base-found-for-revisions","errorCode":null,"errorMessage":"No merge-base found for revisions: {}","messagePattern":"No merge-base found for revisions: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-debug/src/command/revision.rs","lineNumber":139,"sourceCode":"            .entered();\n        graph\n            .find_merge_base_octopus(segments)\n            .map(|segment_id| {\n                graph\n                    .tip_skip_empty(segment_id)\n                    .map(|commit| commit.id)\n                    .with_context(|| {\n                        format!(\n                            \"BUG: Segment {segment_id:?} does not contain a reachable tip commit\"\n                        )\n                    })\n            })\n            .transpose()\n            .context(\"Failed to compute octopus merge-base from graph\")?\n    };\n\n    let Some(merge_base) = merge_base else {\n        bail!(\n            \"No merge-base found for revisions: {}\",\n            merge_base_args.revisions.join(\", \")\n        );\n    };\n    writeln!(out, \"{merge_base}\")?;\n\n    Ok(())\n}\n\nfn args_to_tips(repo: &gix::Repository, graph_args: &RevisionGraphArgs) -> Result<Vec<Tip>> {\n    let mut tips = Vec::new();\n\n    if let Some(tip) = graph_args\n        .target_ref\n        .as_deref()\n        .map(|target_ref| {\n            let mut reference = repo\n                .find_reference(target_ref)","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-debug/src/command/revision.rs#L121-L157","documentation":"`but revision merge-base` computes an octopus merge-base from a commit graph built from the given revisions and their tips; if the graph yields no common ancestor commit (`merge_base` is None), it bails listing the revisions. In practice this means the revisions share no history — unrelated root commits — or the graph traversal couldn't connect them via the configured tips.","triggerScenarios":"Running `but revision merge-base a b` where `a` and `b` have disjoint histories (separate roots, e.g. repositories merged with `--allow-unrelated-histories` splits, grafted/shallow clones missing the connecting history, or substituted refs from different repos).","commonSituations":"Shallow clones where the common ancestor is outside the shallow boundary; grafts/replace refs hiding the real ancestry; comparing branches from unrelated repositories; typo'd revisions that parse but refer to unrelated objects.","solutions":["Verify with git itself: `git merge-base a b` — if git also finds nothing, the histories are genuinely disjoint.","For shallow clones, deepen before asking: `git fetch --unshallow` or `--depth=<n>`.","Double-check each revision string resolves where you think (`git rev-parse <rev>`).","If histories truly share nothing, skip merge-base-dependent logic for these revisions (guard on the error)."],"exampleFix":"# before\nbut revision merge-base feature-a repo-b-branch   # unrelated histories\n\n# after — verify, then decide\ngit merge-base feature-a repo-b-branch || echo 'no common ancestor: disjoint histories'\ngit fetch --unshallow && but revision merge-base feature-a repo-b-branch","handlingStrategy":"try-catch","validationCode":"# Shell — pre-check with git; empty output means no merge-base exists\ngit merge-base -- \"$a\" \"$b\" >/dev/null 2>&1 || { echo 'no common ancestor' >&2; exit 0; }\nbut revision merge-base \"$a\" \"$b\"","typeGuard":null,"tryCatchPattern":"match merge_base_cmd(&repo, &[&a, &b], &mut out) {\n    Ok(()) => {}\n    Err(err) if err.to_string().contains(\"No merge-base found\") => {\n        // disjoint histories: skip merge-base-dependent behavior for this pair\n        tracing::info!(\"{a} and {b} share no ancestry; skipping\");\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Pre-check ancestry with `git merge-base a b` before scripting dependent logic.","Unshallow clones before computing merge-bases across long histories.","Reject cross-repository revision pairs at input validation time."],"tags":["merge-base","graph","cli","unrelated-histories"],"backgroundTag":"no-common-ancestor","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}