{"record":{"id":"c77769c89214ea92","repo":"gitbutlerapp/gitbutler","slug":"no-commits-were-provided-to-move","errorCode":null,"errorMessage":"No commits were provided to move","messagePattern":"No commits were provided to move","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/commit/move_commit.rs","lineNumber":28,"sourceCode":"/// Move multiple commits.\n///\n/// The commits are ordered by parentage before moving so callers do not need to\n/// provide them in graph order.\n///\n/// Each subject is plucked from its old slot - replaced in place by [`Step::None`] -\n/// and inserted relative to `relative_to`. Leaving a placeholder behind means the source\n/// topology is never rewritten, so every reference anchored in it keeps its position and\n/// resolves through the placeholder to the commit below, which is exactly what a branch\n/// a commit was moved out of should do.\npub fn move_commits<'ws, 'meta, M: RefMetadata>(\n    editor: Editor<'ws, 'meta, M>,\n    subject_commit_ids: impl IntoIterator<Item = gix::ObjectId>,\n    relative_to: RelativeTo,\n    side: InsertSide,\n) -> anyhow::Result<SuccessfulRebase<'ws, 'meta, M>> {\n    let subject_commit_ids = subject_commit_ids.into_iter().collect::<Vec<_>>();\n    if subject_commit_ids.is_empty() {\n        bail!(\"No commits were provided to move\")\n    }\n\n    let mut ordered_selectors = editor.order_commit_selectors_by_parentage(subject_commit_ids)?;\n    // Every insert lands adjacent to the anchor, so consecutive inserts stack away from\n    // it. Parentage order already reads base-first, which is what inserting below wants;\n    // inserting above walks the other way.\n    if matches!(side, InsertSide::Above) {\n        ordered_selectors.reverse();\n    }\n\n    let mut editor = editor;\n    let mut plucked = Vec::with_capacity(ordered_selectors.len());\n    for selector in ordered_selectors {\n        // The first-parent edge is the slot the commit sat in and stays with the\n        // placeholder; a merge commit's remaining parents are part of the commit itself\n        // and travel with it.\n        let mut parents = editor.direct_parents(selector)?;\n        parents.sort_by_key(|(_, order)| *order);","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-workspace/src/commit/move_commit.rs#L10-L46","documentation":"Input validation in move_commits: the caller supplied an empty commit list, so there is nothing to move. Like cherry-pick, this is a caller/programming error; at least one commit selector is required for the move operation to proceed.","triggerScenarios":"Calling WorkspaceEditor::move_commits with an empty iterator of gix::ObjectId as subject_commit_ids.","commonSituations":"Scripted moves where the selection list was filtered to empty; forgetting to push IDs into the Vec before the call.","solutions":["Ensure the commit ID list is non-empty before calling move_commits","No-op early in the caller when the selection is empty","Validate user selection at the UI/CLI layer before invoking the API"],"exampleFix":"// before\neditor.move_commits(Vec::new(), relative_to, side)?;\n// after\nif ids.is_empty() { return Ok(()); }\neditor.move_commits(ids, relative_to, side)?;","handlingStrategy":"validation","validationCode":"if subject_commit_ids.is_empty() {\n    return Ok(()); // nothing to move\n}\neditor.move_commits(subject_commit_ids, relative_to, side)?;","typeGuard":"fn has_commits(ids: &[gix::ObjectId]) -> bool { !ids.is_empty() }","tryCatchPattern":"match editor.move_commits(ids, relative_to, side) {\n    Err(e) if e.to_string().contains(\"No commits were provided\") => Ok(()),\n    other => other,\n}","preventionTips":["Validate non-empty selection before calling move_commits","Treat empty input as a caller-level no-op","Check that ID collection logic actually populates the Vec"],"tags":["git","move","empty-input","validation"],"backgroundTag":"missing-required-argument","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"}