{"record":{"id":"cdfdd4cf7380fc77","repo":"GitoxideLabs/gitoxide","slug":"the-review-base-must-be-an-ancestor-of-the-reviewe","errorCode":null,"errorMessage":"the review base must be an ancestor of the reviewed commit","messagePattern":"the review base must be an ancestor of the reviewed commit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/review.rs","lineNumber":119,"sourceCode":"}\n\n#[tracing::instrument(skip_all, fields(%tip, %base))]\npub(crate) fn start(\n    repository_path: &Path,\n    bare: bool,\n    graph: &history::HistoryGraph,\n    tip: ObjectId,\n    base: ObjectId,\n) -> Result<Started> {\n    let repo = open_repository(repository_path, bare, false).context(\"could not open repository to start review\")?;\n    let workdir = repo.workdir().context(\"review requires a worktree\")?.to_owned();\n    let head = repo.head().context(\"could not read HEAD before review\")?;\n    let restore = (\n        head.referent_name().map(ToOwned::to_owned),\n        head.id().map(gix::Id::detach),\n    );\n    if tip == base || !graph.is_ancestor(base, tip) {\n        anyhow::bail!(\"the review base must be an ancestor of the reviewed commit\");\n    }\n    for (label, id) in [(\"reviewed commit\", tip), (\"review base\", base)] {\n        let commit = repo\n            .find_commit(id)\n            .with_context(|| format!(\"could not find {label}\"))?\n            .decode()?\n            .into_owned()?;\n        if super::rebase::is_pending(&commit) {\n            anyhow::bail!(\"{label} has a pending rebase\");\n        }\n    }\n    ensure_clean(&workdir)?;\n\n    let departure_pin = match restore.1 {\n        Some(id) => {\n            let target = restore.0.clone().map_or(Target::Object(id), Target::Symbolic);\n            Some((\n                super::time_travel::create_pin(&repo, target, id, \"tix review departure\")?,","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/review.rs#L101-L137","documentation":"`review::start` validates that the review base is a strict ancestor of the reviewed commit: if `tip == base` or `graph.is_ancestor(base, tip)` is false, a review would have an empty or invalid diff, so it bails. This guarantees every review compares a base strictly below the tip in history.","triggerScenarios":"Calling `review::start` (via `starts_review_with_base_index_and_tip_worktree` and similar flows) with `base` equal to `tip`, or with a `base` that is not an ancestor of `tip` (diverged branches, swapped arguments, base on an unrelated line of history).","commonSituations":"Passing base/tip in the wrong order; reviewing a squashed/rebased commit against a base that was rewritten; accidentally selecting the same commit for both ends; reviewing across diverged branches.","solutions":["Pass a base that is a proper ancestor of the tip (e.g. the merge-base of the branch and main).","Swap the arguments if base and tip were reversed.","Pick a different, earlier commit as the review base.","If tip == base is intended, there is nothing to review — skip the review creation."],"exampleFix":"// before: base may equal or exceed tip\nreview::start(repo, tip_id, tip_id)?; // bails\n// after: derive a valid ancestor base\nlet base = repo.merge_base(base_candidate, tip_id)?;\nassert!(base != tip_id);\nreview::start(repo, base, tip_id)?;","handlingStrategy":"validation","validationCode":"let graph = repo.rewrite_graph()?;\nif tip_id == base_id || !graph.is_ancestor(base_id, tip_id) {\n    // pick a proper ancestor (e.g. merge-base) before starting the review\n}\n","typeGuard":"fn is_valid_review_pair(graph: &Graph, base: ObjectId, tip: ObjectId) -> bool {\n    base != tip && graph.is_ancestor(base, tip)\n}\n","tryCatchPattern":null,"preventionTips":["Derive base from merge-base rather than hardcoding","Always pass (base, tip) in ancestor-descendant order","Refuse to review commits that equal the base (empty diff)"],"tags":["review","ancestor-validation","git"],"backgroundTag":"invalid-argument-value","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}