{"record":{"id":"0793c9f0122dd784","repo":"gitbutlerapp/gitbutler","slug":"kind-commit-cannot-be-the-base-commit","errorCode":null,"errorMessage":"{kind} commit cannot be the base commit","messagePattern":"(.+?) commit cannot be the base commit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-rebase/src/lib.rs","lineNumber":212,"sourceCode":"            RebaseStep::Reference(name) => {\n                if matches!(name, but_core::Reference::Virtual(name) if name.is_empty()) {\n                    return Err(anyhow!(\n                        \"Reference step must have a non-empty virtual branch name\"\n                    ));\n                }\n            }\n        }\n        Ok(())\n    }\n\n    fn assure_unique_step_and_existing_non_base(\n        &self,\n        commit_id: &gix::oid,\n        kind: &str,\n    ) -> Result<()> {\n        self.repo.find_commit(commit_id)?;\n        if Some(commit_id) == self.base.as_deref() {\n            bail!(\"{kind} commit cannot be the base commit\");\n        }\n        if self.steps.iter().any(|s| s.commit_id() == Some(commit_id)) {\n            bail!(\"Picked commit already exists in a previous step\");\n        }\n        Ok(())\n    }\n}\n\n#[instrument(level = \"debug\", skip(repo))]\nfn rebase(\n    repo: &gix::Repository,\n    base: Option<gix::ObjectId>,\n    base_substitute: Option<gix::ObjectId>,\n    steps: Vec<RebaseStep>,\n    pick_mode: PickMode,\n) -> Result<RebaseOutput> {\n    let (mut references, mut commit_mapping) = (\n        vec![],","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-rebase/src/lib.rs#L194-L230","documentation":"but-rebase's `assure_unique_step_and_existing_non_base` validates a Pick or Fixup/Squash step before a rebase plan runs. If the commit referenced by the step is identical to the rebase's base commit (the commit the new history is built on top of), the operation is rejected: you cannot pick or fixup a commit onto itself as the base. This prevents a degenerate plan where a step would rewrite the base commit that is supposed to remain fixed.","triggerScenarios":"Calling a validation path (via `validate_step`) with a `RebaseStep::Pick { commit_id }` or `RebaseStep::SquashIntoPreceding { commit_id }` whose `commit_id` equals `RebaseRequest.base` (compared as `Some(commit_id) == self.base`). The commit must otherwise exist in the repo (`find_commit` succeeds) for the check to be reached.","commonSituations":"Building a rebase plan programmatically from UI selections where the base commit and a picked commit come from the same selection list; off-by-one logic that includes the base commit in the picked list; stale cached commit IDs after the base was changed but the steps weren't recomputed.","solutions":["Remove any step whose commit_id equals the rebase base commit before submitting the plan.","Set the base to the parent of the intended picked commit so the picked commit is rewritten, not used as the base.","Deduplicate/rebuild the step list from the actual base selection to avoid including the base commit as a step."],"exampleFix":"// before\nlet request = RebaseRequest::new(repo, base)\n    .pick(picked)   // picked == base -> error\n    .build();\n// after\nlet steps: Vec<RebaseStep> = all_selected\n    .into_iter()\n    .filter(|c| c != base)\n    .map(|c| RebaseStep::Pick { commit_id: c, new_message: None })\n    .collect();\nlet request = RebaseRequest::new(repo, base).steps(steps).build();","handlingStrategy":"validation","validationCode":"fn step_is_valid_base(step_commit: &gix::oid, base: Option<&gix::oid>) -> bool {\n    Some(step_commit) != base\n}\n// filter before building the plan:\nlet steps: Vec<_> = candidates.into_iter().filter(|c| step_is_valid_base(c, base.as_ref())).collect();","typeGuard":"fn is_not_base(commit_id: &gix::oid, base: &Option<gix::ObjectId>) -> bool {\n    !matches!(base, Some(b) if b == commit_id)\n}","tryCatchPattern":"match request.validate_step(&step) {\n    Err(e) if e.to_string().contains(\"cannot be the base commit\") => {\n        // drop the offending step and rebuild the plan\n    }\n    other => other?,\n}","preventionTips":["Always derive the step list from a selection that excludes the base commit.","Validate every step with validate_step before executing the plan.","Recompute steps whenever the base selection changes."],"tags":["rebase","validation","git"],"backgroundTag":"invalid-argument-value","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}