gitbutlerapp/gitbutler · warning
No uncommitted changes to discard
Error message
No uncommitted changes to discard
What it means
For uncommitted discards, DiffSpecBuilder accumulates specs from the selected uncommitted changes (hunks/files/path-prefixes), reconciles them against the worktree, then ensure! requires at least one resulting spec. The error means the selection resolved to zero actual worktree changes — e.g. the selected hunks were already discarded, files reverted externally, or the selectors matched nothing dirty. Discard then refuses to open a transaction and record an oplog entry for a no-op.
Source
Thrown at crates/but/src/command/legacy/discard.rs:458
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)?;
}
UncommittedDiscardSource::PathPrefix(hunks) => {
builder.push_changes_from_path_prefix(&hunks)?;
}
}
}
}
}
builder.reconcile_worktree_diff_specs()?;
builder.into_diff_specs()
};
anyhow::ensure!(!changes.is_empty(), "No uncommitted changes to discard");
let paths = paths_from_changes(&changes);
ExecutableDiscardOperation::Uncommitted { paths, changes }
}
};
let (mut outcome, mut ws) = but_transaction::with_transaction_with_perm(
ctx,
meta,
perm,
SnapshotDetails::new(oplog_operation_kind),
DryRun::No,
|mut tx| {
let outcome = match executable {
ExecutableDiscardOperation::Branches { branches, commits } => {
if !commits.is_empty() {
tx.discard_commits(commits.iter().map(|c| c.commit_id))?;
}
for branch in &branches {View on GitHub (pinned to caf1f223d3)
Solutions
- Check the worktree is still dirty for those paths: `git status` / `git diff` — if clean, there is nothing to discard.
- Refresh selectors with `but id` and re-run if changes still exist under different IDs.
- Avoid concurrent revert operations while issuing discards.
Example fix
# before $ but discard 2b # hunk 2b was already discarded Error: No uncommitted changes to discard # after $ but id # pick a currently dirty change $ but discard 5f
Defensive patterns
Strategy: validation
Validate before calling
// Confirm the worktree is still dirty before discarding
if repo.status_dirty_paths().is_empty() {
return Ok(()); // nothing uncommitted, nothing to discard
} Try / catch
if let Err(e) = discard_uncommitted(ctx, selection) {
if e.to_string().contains("No uncommitted changes to discard") {
return Ok(()); // benign: selection already clean
}
return Err(e);
} Prevention
- Avoid concurrent editors/reverts while running discard commands.
- Refresh selectors via `but id` immediately before use.
When it happens
Trigger: Calling discard-uncommitted with selectors from a stale ID map after another tool (editor autosave-revert, git checkout --) already cleared the changes; or with filters whose reconcile_worktree_diff_specs() produced an empty set.
Common situations: Two windows both operating on the worktree; retrying a discard that already succeeded; IDE auto-reverting a file between `but id` and the discard call.
Related errors
- No committed changes to discard
- Failed to communicate with LM Studio server: ${error instanc
- When using LM Studio, you must provide a valid endpoint
- Could not discard all selected changes: {refused_paths}
- '{raw_id}' no found
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/960ff4ecf7baa003.
Report an issue: GitHub.