gitbutlerapp/gitbutler · error
Cannot squash commits that would result in merge conflicts
Error message
Cannot squash commits that would result in merge conflicts
What it means
Squashing commits in a GitButler workspace merges the subject commits' changes into the target commit via a tree-level three-way merge (using a force-ours merge strategy). If the resulting tree still contains conflict markers, the library refuses to produce a squash, because the squash would silently embed conflicted content in the commit.
Solutions
- First resolve the overlap: uncommit one of the conflicting changes, resolve it in the working directory, and re-commit before squashing
- Squash the commits one at a time instead of all at once, resolving between steps
- Verify the involved commits don't both modify identical hunks (e.g. via git diff between them)
- If appropriate for the semantics, apply the changes manually and create a single new commit rather than using squash
Example fix
// before but.squash_commits([commit_a, commit_b]); // fails: same lines edited in both // after let outcome = but.uncommit_changes_from_commits([commit_b]); // re-apply conflict-free changes, then: but.squash_commits([commit_a]);
Defensive patterns
Strategy: validation
Validate before calling
let overlaps = detect_overlapping_hunks(&subject_commits, &target_commit)?;
if !overlaps.is_empty() { /* resolve or split before squashing */ } Try / catch
match result {
Err(e) if e.to_string().contains("merge conflicts") => {
// uncommit one side, resolve, retry squash
}
other => other?,
} Prevention
- Check for overlapping hunks between commits before squashing
- Squash commits incrementally rather than in large batches
- Keep workspace commits focused so they rarely touch identical lines
When it happens
Trigger: Calling squash_commits where the target commit's tree and any subject commit's tree touch the same lines/regions so that even merge_options_force_ours cannot cleanly merge them, leaving squashed_tree.conflict set to Some.
Common situations: Users try to squash two workspace commits that edited the same file regions; stacked changes where a later commit rewrites lines an earlier commit rewrote; uncommitted-hunk-level edits overlapping the commit's content.
Understand the failure class
Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.
Related errors
- Cannot merge : merging into / resulted in conflicts. Rebase…
- Cannot squash a commit into itself
- Cannot uncommit changes from a conflicted commit
- Encountered conflict when merging tree
- Failed to apply changes to destination commit - merge…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/146fc4fa8b15a6c2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-workspace/src/commit/squash_commits.rs:177
continue;
}
subject_selectors.push(subject_commit_selector);
}
let subject_commit_ids = subject_selectors
.iter()
.map(|commit_selector| {
let (_, commit) = editor.find_selectable_commit(*commit_selector)?;
Ok(commit.id)
})
.collect::<Result<Vec<_>>>()?;
let squashed_tree = editor.merge_commit_changes_to_tree(
target_commit_obj.id,
subject_commit_ids,
editor.repo().merge_options_force_ours()?,
)?;
if squashed_tree.conflict.is_some() {
bail!("Cannot squash commits that would result in merge conflicts");
}
let mut combined_message = Vec::new();
match how_to_combine_messages {
MessageCombinationStrategy::KeepSubject => {
for source_id in subject_selectors.iter().copied() {
let (_, source_commit) = editor.find_selectable_commit(source_id)?;
push_message_with_spacing(&mut combined_message, source_commit.message.as_ref());
}
}
MessageCombinationStrategy::KeepTarget => {
push_message_with_spacing(&mut combined_message, target_commit_obj.message.as_ref());
}
MessageCombinationStrategy::KeepBoth => {
push_message_with_spacing(&mut combined_message, target_commit_obj.message.as_ref());
for source_id in subject_selectors.iter().copied() {
let (_, source_commit) = editor.find_selectable_commit(source_id)?;
push_message_with_spacing(&mut combined_message, source_commit.message.as_ref());View on GitHub (pinned to 58e5313667)