gitbutlerapp/gitbutler · warning

No committed changes to discard

Error message

No committed changes to discard

What it means

When discarding committed files (DiscardOperation::CommittedFiles), the code builds DiffSpecs for each (source commit, path) pair via DiffSpecBuilder::push_changes_from_committed_file, then asserts the result is non-empty with anyhow::ensure!. The error means every listed path produced no diff against the source commit — nothing would be reverted, so the (transactional, undo-recorded) discard is refused rather than recorded as a no-op.

Source

Thrown at crates/but/src/command/legacy/discard.rs:428

                        commits.push(commit);
                    }
                }
                commits
            };
            ExecutableDiscardOperation::Branches { branches, commits }
        }
        DiscardOperation::Commits(commits) => ExecutableDiscardOperation::Commits(commits),
        DiscardOperation::CommittedFiles { source, paths } => {
            let changes = {
                let context_lines = ctx.settings.context_lines;
                let (repo, ..) = ctx.workspace_and_db_mut_with_perm(perm.read_permission())?;
                let mut builder = DiffSpecBuilder::new(&repo, context_lines);
                for path in &paths {
                    builder.push_changes_from_committed_file(source.commit_id, path.as_bstr())?;
                }
                builder.into_diff_specs()
            };
            anyhow::ensure!(!changes.is_empty(), "No committed changes to discard");
            ExecutableDiscardOperation::CommittedFiles {
                source,
                paths,
                changes,
            }
        }
        DiscardOperation::Uncommitted(selection) => {
            let changes = {
                let context_lines = ctx.settings.context_lines;
                let (repo, ..) = ctx.workspace_and_db_mut_with_perm(perm.read_permission())?;
                let mut builder = DiffSpecBuilder::new(&repo, context_lines);
                match selection {
                    UncommittedSelection::All => builder.push_changes_from_uncommitted_area()?,
                    UncommittedSelection::Changes(changes) => {
                        for change in *changes {
                            match change {
                                UncommittedDiscardSource::HunkOrFile(change) => {
                                    builder.push_changes_from_uncommitted(&change)?;

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Verify there is actually something to revert: `git diff <source_commit> -- <paths>` should show output before you discard.
  2. If files are already restored, no action is needed — this error is the safe no-op guard.
  3. Check exact path spelling/casing against `git ls-tree <commit>` output.

Example fix

# before
$ but discard --files src/main.rs --from <sha>   # already reverted earlier
Error: No committed changes to discard

# after: confirm there is a diff first
$ git diff <sha> -- src/main.rs   # shows hunks, then retry; empty means nothing to do
Defensive patterns

Strategy: validation

Validate before calling

// Confirm a diff exists before discarding committed files
let has_changes = paths.iter().any(|p| {
    repo.diff_tree_to_path(source.commit_id, Some(p)).lines().count() > 0
});
anyhow::ensure!(has_changes, "nothing differs; skip the discard entirely");

Try / catch

if let Err(e) = discard_committed_files(ctx, source, paths) {
    if e.to_string().contains("No committed changes to discard") {
        // already clean — treat as success
        return Ok(());
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling discard-committed-files with paths that are identical in the source commit and the current state (already reverted, or the paths never differed), or with paths misspelled/case-mismatched so each push_changes_from_committed_file contributes nothing.

Common situations: Re-running a discard command from history after the first run already restored the files; path casing on case-insensitive filesystems; passing directory paths expecting recursion when only exact file specs match.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/857eb25cd15bfbeb. Report an issue: GitHub.