{"record":{"id":"1a6af13172ae2089","repo":"GitoxideLabs/gitoxide","slug":"a-squash-is-outside-the-editable-history","errorCode":null,"errorMessage":"a squash is outside the editable history","messagePattern":"a squash is outside the editable history","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/todo.rs","lineNumber":941,"sourceCode":"        let (verb, value) = command.split_once(char::is_whitespace).unwrap_or((command, \"\"));\n        let marked = verb.starts_with('@');\n        let verb = verb.strip_prefix('@').unwrap_or(verb);\n        if marked {\n            if std::mem::replace(&mut command_marker, true) {\n                anyhow::bail!(\"the rebase todo contains more than one @ command\");\n            }\n            if !state.checkout_allowed || repo.workdir().is_none() {\n                anyhow::bail!(\"the rebase todo cannot select a checkout without a worktree\");\n            }\n        }\n        if verb == \"squash\" {\n            let index = section_last_step.context(\"a squash must follow a command in the same fork\")?;\n            let id = resolve_commit(\n                repo,\n                value.split_whitespace().next().context(\"a squash needs a commit ID\")?,\n            )?;\n            if !scope.contains(&id) {\n                anyhow::bail!(\"a squash is outside the editable history\");\n            }\n            if picked.insert(id, index).is_some() {\n                anyhow::bail!(\"a commit is picked more than once\");\n            }\n            steps[index].squash.push(id);\n            if marked {\n                let target = rebase::PlanParent::Step(index);\n                if checkout_target.is_some_and(|checkout| checkout != target) {\n                    anyhow::bail!(\"the @ command and @ reference point to different results\");\n                }\n                checkout_target = Some(target);\n            }\n            section_has_commit = true;\n            continue;\n        }\n        let parent = cursor.context(\"the first todo command must follow a fork heading\")?;\n        let commit = match verb {\n            \"pick\" => {","sourceCodeStart":923,"sourceCodeEnd":959,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/todo.rs#L923-L959","documentation":"Validation inside `edit::todo::parse` of gix-tix. Commands prefixed with `@` (e.g. `@squash`) mark a position in the editable history, but a `squash` verb is only legal when it sits within the history that the todo is allowed to edit. When a squash command's marked position resolves outside that editable history, parsing bails rather than producing a plan that would rewrite commits the tool doesn't own. Triggered by hand-edited todos that move a squash to a foreign segment of history; fix by removing the squash or placing it inside the editable range.","triggerScenarios":"`parse_plan` reads a `squash <oid>` line whose resolved commit is not in the plan's scope set.","commonSituations":"Typing a wrong or truncated commit ID; squashing a commit that lives outside the range forked for editing; copying a squash line from another rebase session.","solutions":["Use a commit ID that is part of the editable history range","Extend the plan's scope if the commit legitimately belongs to the edit","Remove the squash line if the commit should not be folded"],"exampleFix":"// before\nsquash 9999999  # commit outside the edited range\n// after\nsquash abc1234  # commit inside the edited range","handlingStrategy":"validation","validationCode":"let id = repo.rev_parse_single(value)?;\nif !scope.contains(&id) {\n    anyhow::bail!(\"squash target {} is outside the editable history\", id.shorten_or_id());\n}","typeGuard":"fn squash_in_scope(id: gix::Id<'_>, scope: &HashSet<gix::oid::ObjectId>) -> bool {\n    scope.contains(id.object_id())\n}","tryCatchPattern":"match parse_plan(...) {\n    Err(e) if e.to_string().contains(\"a squash is outside the editable history\") => { /* fix the squash line */ }\n    other => other?,\n}","preventionTips":["Only squash commits that appear in the forked range of the plan","Copy commit IDs from the plan's own history, not from other branches","Resolve abbreviated IDs and check scope membership before writing the todo"],"tags":["git","rebase","squash","scope-validation"],"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"}