gitbutlerapp/gitbutler · error

Some selected changes no longer match the worktree's…

Error message

Some selected changes no longer match the worktree's uncommitted changes: {}

What it means

Before moving, the library replays the selected file/hunk specs against the worktree's current uncommitted changes; specs that no longer match are returned in rejected_specs (with a reason). If any spec is rejected, the whole move aborts so the caller never moves a partially stale selection.

Solutions

  1. Re-read the current diff and rebuild the selection immediately before moving
  2. Apply the retry pattern: on this error, refresh the selection from fresh worktree state and re-run (the cleanup code already re-runs sweeps on fresh content)
  3. Have the user re-confirm the selection after any edit
  4. Minimize the window between selection capture and move (no formatter/linter hooks in between)

Example fix

// before: reusing a stale selection
let selection = build_selection(&old_diff);
move_uncommitted_changes(ctx, &wt, Some(selection), None)?;
// after: rebuild from the live diff
let selection = build_selection(&worktree_repo.create_wd_tree(0)?.diff()?);
match move_uncommitted_changes(ctx, &wt, Some(selection), None) {
    Err(e) if e.to_string().contains("no longer match") => retry_with_fresh_selection(),
    r => r,
}
Defensive patterns

Strategy: retry

Validate before calling

// rebuild selection from the CURRENT worktree state right before the move
let current = worktree_repo.create_wd_tree(0)?;
let selection = build_selection(&current.diff()?);
anyhow::ensure!(!selection.is_empty(), "nothing to move");

Try / catch

match move_uncommitted_changes(ctx, &wt, Some(selection), None) {
    Err(e) if e.to_string().contains("no longer match") => {
        let fresh = rebuild_selection_from_live_diff()?;
        move_uncommitted_changes(ctx, &wt, Some(fresh), None)
    }
    r => r,
}

Prevention

When it happens

Trigger: Calling move_uncommitted_changes with a selection captured earlier, while the worktree contents changed in the meantime: files edited/created/deleted, hunks shifted by new edits, line counts no longer matching, or the worktree was rebuilt (create_wd_tree) between capture and move.

Common situations: An agent selecting hunks, then the user (or a formatter/linter) editing the file before the move executes; retries of a move after a first attempt partially ran; long-running sessions where the worktree drifted; concurrent edits from IDE auto-save.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at crates/but-workspace/src/worktrees.rs:203

            worktree_repo.create_wd_tree(0)?
        }
        Some(selection) => {
            if selection.is_empty() {
                bail!("No changes were selected to move");
            }
            let outcome = but_core::tree::create_tree(
                worktree_repo,
                worktree_head_tree,
                selection,
                context_lines,
            )?;
            let rejected: Vec<_> = outcome
                .rejected_specs
                .iter()
                .map(|(reason, spec)| format!("{reason:?}: {}", spec.path))
                .collect();
            if !rejected.is_empty() {
                bail!(
                    "Some selected changes no longer match the worktree's uncommitted changes: {}",
                    rejected.join(", ")
                );
            }
            outcome.destination_tree.context("No changes to move")?
        }
    };
    if moved_tree == worktree_head_tree {
        bail!("No changes to move");
    }

    let destination_outcome = but_core::worktree::safe_checkout_from_head(
        moved_tree,
        main_repo,
        but_core::worktree::checkout::Options {
            merge_base_override: Some(worktree_head_tree),
            allow_uncommitted_changes_to_conflict_with_new_head: true,
            ..Default::default()

View on GitHub (pinned to 58e5313667)