{"record":{"id":"fecf0583bfb2f392","repo":"gitbutlerapp/gitbutler","slug":"no-commits-were-provided-to-cherry-pick","errorCode":null,"errorMessage":"No commits were provided to cherry-pick","messagePattern":"No commits were provided to cherry-pick","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/commit/cherry_pick.rs","lineNumber":34,"sourceCode":"/// Sources are read from the object database, so they may live anywhere in the repository,\n/// including on branches that aren't part of the workspace. Duplicates are dropped, keeping the\n/// first occurrence, and the rest are applied in the order given rather than reordered, like\n/// `git cherry-pick`: the first source lands at `side` of `relative_to`, and each later one\n/// directly above the one before it.\n/// Child commits, and the target commit, if applicable, are rebased atop the cherry-picked commits.\npub fn cherry_pick_commits<'ws, 'meta, M: RefMetadata>(\n    mut editor: Editor<'ws, 'meta, M>,\n    source_commits: impl IntoIterator<Item = gix::ObjectId>,\n    relative_to: RelativeTo,\n    side: InsertSide,\n) -> anyhow::Result<(SuccessfulRebase<'ws, 'meta, M>, Vec<Selector>)> {\n    let mut seen = HashSet::new();\n    let sources = source_commits\n        .into_iter()\n        .filter(|id| seen.insert(*id))\n        .collect::<Vec<_>>();\n    if sources.is_empty() {\n        bail!(\"No commits were provided to cherry-pick\")\n    }\n    if matches!(\n        (&relative_to, side),\n        (RelativeTo::Reference(_), InsertSide::Above)\n    ) {\n        bail!(\"Cannot cherry-pick above a reference\")\n    }\n\n    let target = relative_to.to_selector(&editor)?;\n\n    let mut inserted_selectors = Vec::with_capacity(sources.len());\n    let mut previous_selector = None;\n    for source in sources {\n        // Give the copy its own change ID, retaining all other metadata.\n        let mut template = editor.find_commit(source)?;\n        let mut headers = Headers::try_from_commit(&template.inner).unwrap_or_default();\n        headers.change_id = Headers::from_config(&editor.repo().config_snapshot()).change_id;\n        headers.set_in_commit(&mut template.inner);","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-workspace/src/commit/cherry_pick.rs#L16-L52","documentation":"cherry_pick_commits deduplicates the input ids into a Vec and bails when the result is empty. There is nothing to apply, and proceeding would create an empty rebase outcome, so it fails fast. This is a pure caller-input error; no editor state has been consumed.","triggerScenarios":"Calling cherry_pick_commits with an empty iterator, or with an iterator whose items all deduplicate away (single id repeated is still one entry — only zero unique ids triggers this).","commonSituations":"UI 'cherry-pick selected commits' invoked with an empty selection; upstream list filtered down to nothing before the call; batch loops where one chunk is legitimately empty.","solutions":["Guard the call: if the selection is empty, skip the operation (no-op) instead of invoking the API.","Fix the caller that produced an empty commit list (selection state, filter bug).","In batch processing, filter empty batches before calling."],"exampleFix":"// before\ncherry_pick_commits(editor, selected_ids, relative_to, side)?;\n\n// after\nif selected_ids.is_empty() {\n    return Ok((successful_rebase, vec![])); // nothing to pick\n}\ncherry_pick_commits(editor, selected_ids, relative_to, side)?;","handlingStrategy":"validation","validationCode":"let ids: Vec<_> = source_commits.into_iter().collect::<HashSet<_>>().into_iter().collect();\nif ids.is_empty() {\n    // nothing selected: no-op instead of an API error\n    return Ok((successful_rebase, vec![]));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Require a non-empty selection before enabling cherry-pick actions.","Guard batch callers: skip empty chunks instead of invoking the API.","Unit-test boundary: empty iterator and single-id iterator."],"tags":["gitbutler","cherry-pick","validation","empty-input","rust"],"backgroundTag":"empty-input-collection","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}