{"record":{"id":"aa585598e159441d","repo":"GitoxideLabs/gitoxide","slug":"moving-a-stack-cannot-rewrite-root-or-merge-commit","errorCode":null,"errorMessage":"moving a stack cannot rewrite root or merge commits","messagePattern":"moving a stack cannot rewrite root or merge commits","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/rebase.rs","lineNumber":705,"sourceCode":"        .descendants_in_parent_order(base)\n        .context(\"the stack base is not in the loaded history\")?\n        .into_iter()\n        .chain(\n            graph\n                .descendants_in_parent_order(target)\n                .context(\"the move target is not in the loaded history\")?,\n        )\n    {\n        if (id != target || target_rewritten) && scope_set.insert(id) {\n            scope.push(id);\n        }\n    }\n\n    let mut new_parent = HashMap::with_capacity(scope.len());\n    for id in &scope {\n        let parents = graph.parents_of(*id).context(\"an affected move commit is incomplete\")?;\n        let [parent] = parents.as_slice() else {\n            anyhow::bail!(\"moving a stack cannot rewrite root or merge commits\");\n        };\n        new_parent.insert(\n            *id,\n            if *id == base {\n                target\n            } else if stack_set.contains(id) {\n                *parent\n            } else if let Some(old_parent) = stack_parent.get(parent) {\n                *old_parent\n            } else if *parent == target {\n                head\n            } else {\n                *parent\n            },\n        );\n    }\n\n    let mut steps = Vec::with_capacity(scope.len());","sourceCodeStart":687,"sourceCodeEnd":723,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/rebase.rs#L687-L723","documentation":"After determining the move, the plan computes new parents for every affected commit (stack commits plus descendants of base and target). Each affected commit must have exactly one parent for the re-parenting map to be well-defined; root or merge commits among the affected set cannot be rewritten, so this error is raised.","triggerScenarios":"Calling `move_insert_plan`/`stack_insert_plan` where any commit in scope — descendants of `base` or of `target` (when target is rewritten) — is a root or merge commit, detected during the `new_parent` computation loop.","commonSituations":"Moving a stack under/over a region of history containing merge commits; repositories where the insertion target has merge descendants that must be rewritten.","solutions":["Choose a move target whose affected descendant set is linear.","Linearize the merge-heavy region (rebase without merges) before moving the stack.","Restrict the move to a region of history without merges, adjusting base/target accordingly."],"exampleFix":"// before\ntix move-stack --base base --head HEAD --onto <merge-adjacent-target>\n\n// after\nlet affected: Vec<_> = affected_scope(&graph, base, target)?;\nif affected.iter().any(|id| graph.parents_of(*id)?.len() != 1) {\n    eprintln!(\"move would rewrite a merge commit\");\n    return Ok(());\n}\ntix move-stack --base base --head HEAD --onto target","handlingStrategy":"validation","validationCode":"// verify all commits whose parents will be rewritten are linear\nfor id in affected_scope_ids(&graph, base, target)? {\n    if graph.parents_of(id)?.len() != 1 {\n        eprintln!(\"move would rewrite a root or merge commit\");\n        return Ok(());\n    }\n}","typeGuard":"fn move_scope_is_linear(graph: &HistoryGraph, base: ObjectId, target: ObjectId) -> bool {\n    let scope = |t| graph.descendants_in_parent_order(t).unwrap_or_default();\n    scope(base).iter().chain(scope(target).iter())\n        .all(|id| graph.parents_of(*id).map(|p| p.len() == 1).unwrap_or(false))\n}","tryCatchPattern":"match stack_insert_plan(&repo, &graph, base, head, target) {\n    Err(e) if e.to_string().contains(\"root or merge commits\") => eprintln!(\"choose a target whose rewrite scope is linear\"),\n    other => other?,\n}","preventionTips":["Inspect descendants of both base and target before moving in merge-heavy histories","Linearize merges in the affected region before stack operations","Prefer regions of history verified linear when offering stack-move destinations"],"tags":["git","rebase","merge-commit","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}