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
- Select fewer hunks — drop the hunk that overlaps and uncommit the rest
- Uncommit the whole commit instead of individual hunks (whole-commit moves avoid intra-commit collisions)
- Clean or commit the workspace's overlapping changes in that file first, then retry the hunk selection
- 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
- Select fewer hunks when a dry run conflicts; overlap is almost always the cause
- Prefer whole-commit uncommit when intra-commit hunk overlaps appear
- Commit or stash workspace edits in the same file before extracting hunks
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
- Cannot uncommit commits that would result in merge conflicts
- Failed to communicate with LM Studio server: ${error instanc
- When using OpenRouter, you must provide a valid API key
- HTTP Error ${response.statusText}: ${text}
- failed to discover GitButler branch with 'but --json status'
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/b0cf9ba5cf429059.
Report an issue: GitHub.