{"record":{"id":"8440bac8a9deb517","repo":"GitoxideLabs/gitoxide","slug":"the-stack-base-must-be-an-ancestor-of-head","errorCode":null,"errorMessage":"the stack base must be an ancestor of HEAD","messagePattern":"the stack base must be an ancestor of HEAD","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/rebase.rs","lineNumber":653,"sourceCode":"    graph: &HistoryGraph,\n    source: ObjectId,\n    target: ObjectId,\n) -> Result<Plan> {\n    stack_insert_plan(repo, graph, source, source, target)\n}\n\npub(crate) fn stack_insert_plan(\n    repo: &gix::Repository,\n    graph: &HistoryGraph,\n    base: ObjectId,\n    head: ObjectId,\n    target: ObjectId,\n) -> Result<Plan> {\n    if repo.head_id()?.detach() != head {\n        anyhow::bail!(\"the move source must be the current HEAD\");\n    }\n    if !graph.is_ancestor(base, head) {\n        anyhow::bail!(\"the stack base must be an ancestor of HEAD\");\n    }\n    graph\n        .parents_of(target)\n        .context(\"the move target is not in the loaded history\")?;\n\n    let mut stack = vec![head];\n    let mut stack_parent = HashMap::new();\n    loop {\n        let id = *stack.last().expect(\"a stack always contains HEAD\");\n        let parents = graph.parents_of(id).context(\"a moved stack commit is incomplete\")?;\n        let [parent] = parents.as_slice() else {\n            anyhow::bail!(\"moving a stack requires every commit to have exactly one parent\");\n        };\n        stack_parent.insert(id, *parent);\n        if id == base {\n            break;\n        }\n        stack.push(*parent);","sourceCodeStart":635,"sourceCodeEnd":671,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/rebase.rs#L635-L671","documentation":"The stack-insert operation moves the contiguous linear run of commits from `base` up to `head`. For this run to exist, `base` must be an ancestor of `head`; otherwise there is no well-defined stack to move. `graph.is_ancestor(base, head)` returning false triggers this bail.","triggerScenarios":"Calling `move_insert_plan`/`stack_insert_plan(repo, graph, base, head, target)` where `base` is not an ancestor of `head` — e.g. passing two commits on divergent branches, or `base` on a branch that doesn't contain HEAD's history.","commonSituations":"Selecting a 'stack start' commit in a UI from a different branch than HEAD; scripts computing base/head pairs from the wrong range; history changed (rebase) so the previously valid base is no longer an ancestor.","solutions":["Pass a `base` that is an ancestor of `head`, typically the commit just below the stack you want to move.","Verify with the graph before calling: `graph.is_ancestor(base, head)`.","For moving a single commit, use `move_insert_plan` with base == head instead of a custom base."],"exampleFix":"// before\nstack_insert_plan(&repo, &graph, unrelated_base, head, target)?\n\n// after\nanyhow::ensure!(graph.is_ancestor(base, head), \"base must be an ancestor of HEAD\");\nstack_insert_plan(&repo, &graph, base, head, target)?","handlingStrategy":"validation","validationCode":"if !graph.is_ancestor(base, head) {\n    eprintln!(\"base must be an ancestor of head\");\n    return Ok(());\n}","typeGuard":"fn is_valid_stack(graph: &HistoryGraph, base: ObjectId, head: ObjectId) -> bool {\n    graph.is_ancestor(base, head)\n}","tryCatchPattern":"match stack_insert_plan(&repo, &graph, base, head, target) {\n    Err(e) if e.to_string().contains(\"ancestor of HEAD\") => eprintln!(\"base is not on HEAD's history; pick a base below the stack\"),\n    other => other?,\n}","preventionTips":["Derive base from the graph (e.g. walk parents from head) instead of accepting arbitrary ids","Restrict UI stack-base selection to commits on HEAD's first-parent chain","Re-verify ancestry after any history-changing operation"],"tags":["git","rebase","ancestry","invalid-argument"],"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-16T04:17:20.429Z"}