Merge commit diffs show all incoming changes instead of merge-only changes
#12.795 aperta il 12 mar 2026
Metriche repository
- Star
- (19.787 star)
- Metriche merge PR
- (Merge medio 14h 43m) (446 PR mergiate in 30 g)
Descrizione
When a branch contains merge commits, the diff view shows all changes introduced by the merged branch rather than just the changes unique to the merge itself (conflict resolutions, manual edits). For example, merging origin/dev into a feature branch shows 65 changed files (+973/-3928) in GitButler, while GitHub shows 24 files for the same PR — because GitHub diffs against the merge-base.
Root cause
CommitDetails::from_commit_id() in crates/but-core/src/diff/commit_details.rs and commit_changes_with_line_stats_by_worktree_dir() in crates/but-core/src/diff/ui.rs both take only the first parent for diffing:
let first_parent_commit_id = commit.parent_ids().map(|id| id.detach()).next();
For regular commits this is correct. For merge commits, the first parent is the branch being merged into, so the diff includes everything from the other branch.
Proposed fix
For commits with >1 parent, diff against the merge-base of the parents instead of the first parent. This shows only what the merge introduced (conflict resolutions + manual changes), matching GitHub's behavior. The merge-base pattern already exists in the codebase (but-rebase/src/graph_rebase/cherry_pick.rs).
The change would be ~20 lines across the two functions. No frontend changes needed since the JSON serialization already maps diff_with_first_parent to changes.
Happy to put up a PR if this approach makes sense — or if a toggle between first-parent and merge-base diff would be preferred.