{"record":{"id":"5bf1e16d23c54438","repo":"GitoxideLabs/gitoxide","slug":"a-commit-is-picked-more-than-once","errorCode":null,"errorMessage":"a commit is picked more than once","messagePattern":"a commit is picked more than once","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/todo.rs","lineNumber":944,"sourceCode":"        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\" => {\n                let value = value.split_whitespace().next().context(\"a pick needs a commit ID\")?;\n                let resolved_id = state.resolved;\n                let full_null = resolved_id.is_some_and(|id| {","sourceCodeStart":926,"sourceCodeEnd":962,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/todo.rs#L926-L962","documentation":"Thrown when the same commit would be applied more than once by the plan, either by a `pick` line or by a `squash` line referencing it. Duplicate application would create ambiguous or duplicated history, so the parser tracks a `picked` map of commit ID to step index and rejects repeats.","triggerScenarios":"`parse_plan` sees two commands referencing the same commit ID — e.g. a `pick abc123` followed by `squash abc123`, or the same commit picked twice.","commonSituations":"Copy-pasting todo lines; generated todos that include a commit both as a pick and as a squash source; accidentally re-adding a commit after an edit.","solutions":["Remove or reword the duplicate line so each commit appears once","Squash a different commit into the step instead of one already picked","De-duplicate the todo text before calling the parser"],"exampleFix":"// before\npick abc123\nsquash abc123  # duplicate\n// after\npick abc123","handlingStrategy":"validation","validationCode":"let mut seen = HashSet::new();\nfor line in todo.lines() {\n    if let Some(id) = line.split_whitespace().nth(1) {\n        if !seen.insert(id.to_owned()) { anyhow::bail!(\"commit {id} used more than once\"); }\n    }\n}","typeGuard":"fn is_unique_pick(id: &str, picked: &HashSet<String>) -> bool {\n    !picked.contains(id)\n}","tryCatchPattern":"match parse_plan(...) {\n    Err(e) if e.to_string().contains(\"picked more than once\") => { /* de-duplicate the todo */ }\n    other => other?,\n}","preventionTips":["De-duplicate commit IDs across pick and squash lines before parsing","Never squash a commit that is also picked elsewhere","Track applied commit IDs when generating todos in scripts"],"tags":["git","rebase","duplicate","todo-parsing"],"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"}