gitbutlerapp/gitbutler · error · anyhow::Error

Cannot uncommit hunks that would result in merge conflicts

Error message

Cannot uncommit hunks that would result in merge conflicts

What it means

Hunk-level variant of the uncommit conflict guard: selected hunks are simulated via `commit_uncommit_changes_only_with_perm(..., DryRun::Yes)`, and if the simulated workspace reports conflicts the operation aborts before `commit_uncommit_changes_with_perm(..., DryRun::No)` performs the real move. It means the specific hunks you picked collide with other content in the workspace.

Source

Thrown at crates/but/src/command/legacy/squash.rs:1454

                } => SquashOutcome::UncommitBranch {
                    branch_names: source_branches,
                },
            };
            Ok((outcome, Some(ws)))
        }
        ExecutableSquashOperation::UncommitHunks { source, changes } => {
            {
                let but_api::commit::types::MoveChangesResult { workspace } =
                    but_api::commit::uncommit::commit_uncommit_changes_only_with_perm(
                        ctx,
                        source.commit_id,
                        changes.clone(),
                        None,
                        DryRun::Yes,
                        perm,
                    )?;

                anyhow::ensure!(
                    !workspace.is_conflicted(),
                    "Cannot uncommit hunks that would result in merge conflicts"
                );
            }

            let but_api::commit::types::MoveChangesResult { workspace: _ } =
                but_api::commit::uncommit::commit_uncommit_changes_with_perm(
                    ctx,
                    source.commit_id,
                    changes,
                    None,
                    DryRun::No,
                    perm,
                )?;

            Ok((SquashOutcome::UncommitHunk { source }, None))
        }
    }

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Select fewer hunks — drop the hunk that overlaps and uncommit the rest
  2. Uncommit the whole commit instead of individual hunks (whole-commit moves avoid intra-commit collisions)
  3. Clean or commit the workspace's overlapping changes in that file first, then retry the hunk selection
  4. Reorder work: ship or uncommit the dependent later commits before extracting the hunk

Example fix

# before: hunk selection that collides with kept content
but squash --uncommit-hunks c3 :1,3

# after: whole-commit uncommit, no hunk overlap
but squash --uncommit c3
Defensive patterns

Strategy: validation

Validate before calling

let but_api::commit::types::MoveChangesResult { workspace, .. } =
    but_api::commit::uncommit::commit_uncommit_changes_only_with_perm(
        ctx, commit_id, changes.clone(), None, DryRun::Yes, perm,
    )?;
if workspace.is_conflicted() {
    anyhow::bail!("hunk selection would conflict; drop overlapping hunks or uncommit the whole commit");
}

Type guard

fn dry_run_is_conflicted(workspace: &but_graph::Workspace) -> bool {
    workspace.is_conflicted()
}

Try / catch

match run_uncommit_hunks(ctx, commit_id, changes, perm) {
    Ok(result) => { /* use result */ }
    Err(err) if err.to_string().contains("hunks that would result in merge conflicts") => {
        // retry with fewer hunks or fall back to whole-commit uncommit
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Uncommitting an individual hunk that overlaps lines also modified by other hunks kept in the commit, by later commits in the stack, or by existing workspace changes — the dry run ends conflicted.

Common situations: Fine-grained hunk splitting inside a commit where later commits edited adjacent/same lines; picking partial hunks while the workspace is dirty in the same file.

Related errors


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