gitbutlerapp/gitbutler · error

Source commit must not be conflicted

Error message

Source commit must not be conflicted

What it means

move_changes_between_commits requires the source commit to be conflict-free, because it computes a new tree by removing the described diffs from the source tree — impossible to do reliably on a conflicted tree. It bails before any tree rewrite.

Solutions

  1. Resolve the source commit's conflicts first, then retry the move
  2. Pick a different source commit that is not conflicted
  3. Abort the conflicted operation and redo it before moving changes

Example fix

// before
editor.move_changes_between_commits(conflicted_src, dst, changes, ctx)?;
// after
if conflicted_src.attach(repo).is_conflicted() { resolve_first()?; }
editor.move_changes_between_commits(conflicted_src, dst, changes, ctx)?;
Defensive patterns

Strategy: validation

Validate before calling

if source.attach(editor.repo()).is_conflicted() {
    bail!("resolve source conflicts before moving changes");
}
editor.move_changes_between_commits(source_selector, dest_selector, changes, ctx)?;

Type guard

fn moveable(commit: &gix::Commit) -> bool { !commit.clone().attach(commit.repo).is_conflicted() }

Try / catch

match editor.move_changes_between_commits(src, dst, changes, ctx) {
    Err(e) if e.to_string().contains("Source commit must not be conflicted") => resolve_then_retry(src),
    other => other,
}

Prevention

When it happens

Trigger: Calling move_changes_between_commits (or any wrapper like move_file_between_commits) where source_commit.clone().attach(repo).is_conflicted() is true.

Common situations: Moving file changes out of a commit that is mid-conflict after a rebase/merge; automated reassignment flows that don't check commit conflict state first.

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/efa9d02f71638519. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-workspace/src/commit/move_changes.rs:67

    let (destination_selector, destination_commit) =
        editor.find_selectable_commit(destination_commit)?;

    // Early return if source and destination are the same
    if source_commit.id == destination_commit.id {
        // Select the commit to get a valid selector, then just rebase (no-op)
        let outcome = editor.rebase()?;
        return Ok(MoveChangesOutcome {
            rebase: outcome,
            source_selector,
            destination_selector,
        });
    }

    // Step 1: Get the source commit and its tree
    let source_tree_id = {
        let source_commit = source_commit.clone().attach(editor.repo());
        if source_commit.is_conflicted() {
            bail!("Source commit must not be conflicted")
        }
        source_commit.tree
    };

    let (source_tree_without_changes_id, dropped_diffs) = create_tree_without_diff(
        editor.repo(),
        ChangesSource::Commit {
            id: source_commit.id,
        },
        changes_to_move,
        context_lines,
    )?;

    if !dropped_diffs.is_empty() {
        bail!("Failed to extract described changes from source commit");
    }

    let new_source_commit_id = {

View on GitHub (pinned to 58e5313667)