gitbutlerapp/gitbutler · error

Destination commit must not be conflicted

Error message

Destination commit must not be conflicted

What it means

Guard in move_changes_between_commits: the destination commit currently carries conflicts, so moving changes into it would compound an unresolved state. The operation is refused until the user resolves the destination commit's conflicts, after which the move can be retried.

Solutions

  1. Resolve conflicts in the destination commit before moving changes into it
  2. Choose a non-conflicted destination commit
  3. Re-run the rebase resolving conflicts, then retry the move

Example fix

// before
editor.move_changes_between_commits(src, conflicted_dst, changes, ctx)?;
// after
resolve_conflicts_in(conflicted_dst)?;
editor.move_changes_between_commits(src, conflicted_dst, changes, ctx)?;
Defensive patterns

Strategy: validation

Validate before calling

let (_, dst) = editor.find_selectable_commit(dest_selector)?;
if dst.clone().attach(editor.repo()).is_conflicted() {
    bail!("resolve destination conflicts first");
}

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("Destination commit must not be conflicted") => resolve_then_retry(dst),
    other => other,
}

Prevention

When it happens

Trigger: move_changes_between_commits finds the (rebased) destination commit conflicted via is_conflicted() before applying the changes to its tree.

Common situations: Moving changes into a commit that sits behind a conflict introduced by a rebase; destination commit already carried conflict markers from a prior operation.

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

Appendix: source

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

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

    let new_source_commit_id = {
        let mut new_source_commit = source_commit.clone();
        new_source_commit.tree = source_tree_without_changes_id;
        editor.new_commit(new_source_commit, DateMode::CommitterUpdateAuthorKeep)?
    };

    editor.replace(source_selector, Step::new_pick(new_source_commit_id))?;

    // Rebase and get potentially rebased destination commit
    let mut editor = editor.rebase()?.into_editor();
    let (_, rebased_destination_commit) = editor.find_selectable_commit(destination_selector)?;
    let destination_tree_id = {
        let rebased_destination_commit = rebased_destination_commit.clone().attach(editor.repo());
        if rebased_destination_commit.is_conflicted() {
            bail!("Destination commit must not be conflicted")
        }
        rebased_destination_commit.tree
    };

    let destination_tree_with_changes = {
        let repo = editor.repo();
        let (fail_fast_options, conflict_kind) = repo.merge_options_fail_fast()?;
        let mut merge_result = repo.merge_trees(
            source_tree_without_changes_id,
            source_tree_id,
            destination_tree_id,
            Default::default(),
            fail_fast_options,
        )?;

        if merge_result.has_unresolved_conflicts(conflict_kind) {
            bail!("Failed to apply changes to destination commit - merge conflict");
        }

View on GitHub (pinned to 58e5313667)