{"record":{"id":"7ae23ce979db4cc6","repo":"gitbutlerapp/gitbutler","slug":"no-changes-were-provided-to-uncommit","errorCode":null,"errorMessage":"No changes were provided to uncommit","messagePattern":"No changes were provided to uncommit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/commit/uncommit_changes.rs","lineNumber":98,"sourceCode":"        rebase,\n        commit_selector,\n    })\n}\n\n/// Removes changes from multiple commits, grouped by commit id and applied in\n/// child-to-parent order.\n///\n/// Invalid or inapplicable grouped sources are collected in `failures`. When at\n/// least one source succeeds, all successful replacements are rebased once at\n/// the end. When no source succeeds, `rebase` is `None`.\npub fn uncommit_changes_from_commits<'ws, 'meta, M: RefMetadata>(\n    mut editor: Editor<'ws, 'meta, M>,\n    sources: impl IntoIterator<Item = UncommitChangesSource>,\n    context_lines: u32,\n) -> Result<UncommitChangesFromCommitsOutcome<'ws, 'meta, M>> {\n    let groups = group_sources_by_commit(sources);\n    if groups.is_empty() {\n        bail!(\"No changes were provided to uncommit\")\n    }\n\n    // Index groups by commit id so the apply loop below is O(n) rather than\n    // re-scanning `groups` for every ordered commit. Each commit id is unique\n    // after grouping, so this map is 1:1.\n    let group_by_commit: HashMap<gix::ObjectId, usize> = groups\n        .iter()\n        .enumerate()\n        .map(|(index, group)| (group.commit_id, index))\n        .collect();\n\n    let mut failures = Vec::new();\n    let mut valid_commit_ids = Vec::new();\n    for group in &groups {\n        match editor.find_selectable_commit(group.commit_id) {\n            Ok((_selector, commit)) => {\n                if commit.clone().attach(editor.repo()).is_conflicted() {\n                    failures.push(failure(","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-workspace/src/commit/uncommit_changes.rs#L80-L116","documentation":"uncommit_changes_from_commits requires at least one change source (a commit or reference to changes). After grouping the provided sources by commit id, if the resulting group list is empty there is nothing to uncommit, so the function bails early instead of producing a meaningless outcome.","triggerScenarios":"Calling uncommit_changes_from_commits with an empty iterator of UncommitChangesSource, or with sources that all filter/group down to nothing (e.g. an empty slice passed programmatically).","commonSituations":"UI/CLI code that collects selected changes and passes an empty selection; automation scripts where an earlier step produced no selections; callers that skip the empty-input check.","solutions":["Check that the source list is non-empty before calling; return early in the caller if nothing is selected","If the input derives from user selection, prompt the user to select changes first","Treat the error as a no-op signal in batch flows and continue"],"exampleFix":"// before\nbut.uncommit_changes_from_commits(selection); // panics/bails when selection is empty\n// after\nif selection.is_empty() { return Ok(()); }\nbut.uncommit_changes_from_commits(selection);","handlingStrategy":"validation","validationCode":"if sources.is_empty() { return; } // skip call entirely\nbut.uncommit_changes_from_commits(editor, sources, context_lines)?;","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"No changes were provided\") => Ok(Default::default()), // treat as no-op\n    other => other,\n}","preventionTips":["Always check selection emptiness at the UI/CLI boundary","Fail fast in callers that gather change sources","Treat empty input as an explicit no-op path"],"tags":["git","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"}