gitbutlerapp/gitbutler · error

No changes were provided to uncommit

Error message

No changes were provided to uncommit

What it means

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.

Solutions

  1. Check that the source list is non-empty before calling; return early in the caller if nothing is selected
  2. If the input derives from user selection, prompt the user to select changes first
  3. Treat the error as a no-op signal in batch flows and continue

Example fix

// before
but.uncommit_changes_from_commits(selection); // panics/bails when selection is empty
// after
if selection.is_empty() { return Ok(()); }
but.uncommit_changes_from_commits(selection);
Defensive patterns

Strategy: validation

Validate before calling

if sources.is_empty() { return; } // skip call entirely
but.uncommit_changes_from_commits(editor, sources, context_lines)?;

Try / catch

match result {
    Err(e) if e.to_string().contains("No changes were provided") => Ok(Default::default()), // treat as no-op
    other => other,
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/7ae23ce979db4cc6. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-workspace/src/commit/uncommit_changes.rs:98

        rebase,
        commit_selector,
    })
}

/// Removes changes from multiple commits, grouped by commit id and applied in
/// child-to-parent order.
///
/// Invalid or inapplicable grouped sources are collected in `failures`. When at
/// least one source succeeds, all successful replacements are rebased once at
/// the end. When no source succeeds, `rebase` is `None`.
pub fn uncommit_changes_from_commits<'ws, 'meta, M: RefMetadata>(
    mut editor: Editor<'ws, 'meta, M>,
    sources: impl IntoIterator<Item = UncommitChangesSource>,
    context_lines: u32,
) -> Result<UncommitChangesFromCommitsOutcome<'ws, 'meta, M>> {
    let groups = group_sources_by_commit(sources);
    if groups.is_empty() {
        bail!("No changes were provided to uncommit")
    }

    // Index groups by commit id so the apply loop below is O(n) rather than
    // re-scanning `groups` for every ordered commit. Each commit id is unique
    // after grouping, so this map is 1:1.
    let group_by_commit: HashMap<gix::ObjectId, usize> = groups
        .iter()
        .enumerate()
        .map(|(index, group)| (group.commit_id, index))
        .collect();

    let mut failures = Vec::new();
    let mut valid_commit_ids = Vec::new();
    for group in &groups {
        match editor.find_selectable_commit(group.commit_id) {
            Ok((_selector, commit)) => {
                if commit.clone().attach(editor.repo()).is_conflicted() {
                    failures.push(failure(

View on GitHub (pinned to 58e5313667)