Skip to content

Commit d582c07

Browse files
committed
Add tests for Myers false-positive merge conflicts
Reproduce the gitoxide Myers diff bug (GitoxideLabs/gitoxide#2475) in the context of GitButler workspace management. The bug causes non-overlapping edits to the same file to be reported as conflicts, which leads to branches being falsely unapplied from the workspace. Test fixtures (shell scenarios): - myers-false-conflict-same-file.sh: two branches each deleting a different line from a shared file (delete-alpha, delete-bravo). - myers-false-conflict-multi-commit.sh: same pattern but with two sequential commits per branch, for squash/amend coverage. Test cases (myers_false_conflict.rs): - Basic merge: both stacks should merge cleanly, but the second branch is falsely unapplied. - Hero stack: hero is preserved, non-hero is falsely unapplied. - Multi-commit branches: same false unapply with deeper history. - Squash then merge: squash succeeds but subsequent workspace merge still falsely unapplies the other branch. - Amend then merge: amend succeeds but workspace merge still falsely unapplies the other branch. - Stack ordering: the false conflict is symmetric — the second stack is always the one unapplied regardless of order. All five conflict-related tests currently fail against unpatched gitoxide and should pass once the upstream fix lands.
1 parent edf8349 commit d582c07

File tree

4 files changed

+457
-0
lines changed

4 files changed

+457
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu -o pipefail
4+
source "${BASH_SOURCE[0]%/*}/shared.sh"
5+
6+
### Description
7+
# Similar to myers-false-conflict-same-file but with multiple sequential commits
8+
# per branch, to test squash and amend operations in the context of false conflicts.
9+
#
10+
# Base file:
11+
# alpha_x
12+
# (blank)
13+
# bravo_x
14+
# charlie_x
15+
# (blank)
16+
#
17+
# Branch "edit-alpha" has two commits:
18+
# 1. Adds a comment line at the top
19+
# 2. Deletes alpha_x (replaces with blank) and removes trailing blank
20+
#
21+
# Branch "edit-bravo" has two commits:
22+
# 1. Adds a comment line at the bottom
23+
# 2. Deletes bravo_x
24+
#
25+
# The final state of each branch triggers the Myers false conflict.
26+
# Squashing the two commits in either branch should also work but may
27+
# trigger merge issues during the rebase.
28+
29+
git init
30+
31+
# Create the base content on main
32+
printf 'alpha_x\n\nbravo_x\ncharlie_x\n\n' > shared-file
33+
git add shared-file
34+
git commit -m "base: shared-file with alpha, bravo, charlie"
35+
36+
git branch gitbutler/workspace
37+
38+
# Branch A: two sequential commits
39+
git checkout -b edit-alpha main
40+
41+
# First commit: add a header comment (doesn't conflict with anything)
42+
printf '# header\nalpha_x\n\nbravo_x\ncharlie_x\n\n' > shared-file
43+
git add shared-file
44+
git commit -m "add header to shared-file"
45+
46+
# Second commit: delete alpha_x and trailing blank
47+
printf '# header\n\n\nbravo_x\ncharlie_x\n' > shared-file
48+
git add shared-file
49+
git commit -m "delete alpha_x from shared-file"
50+
51+
# Branch B: two sequential commits
52+
git checkout -b edit-bravo main
53+
54+
# First commit: add a footer comment (doesn't conflict with anything)
55+
printf 'alpha_x\n\nbravo_x\ncharlie_x\n\n# footer\n' > shared-file
56+
git add shared-file
57+
git commit -m "add footer to shared-file"
58+
59+
# Second commit: delete bravo_x
60+
printf 'alpha_x\n\ncharlie_x\n\n# footer\n' > shared-file
61+
git add shared-file
62+
git commit -m "delete bravo_x from shared-file"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu -o pipefail
4+
source "${BASH_SOURCE[0]%/*}/shared.sh"
5+
6+
### Description
7+
# Two independent branches editing the same file with non-overlapping changes.
8+
# This triggers a false merge conflict with Myers diff algorithm due to
9+
# split hunks with empty insertions.
10+
# See: https://github.com/GitoxideLabs/gitoxide/issues/2475
11+
#
12+
# Base file has:
13+
# alpha_x
14+
# (blank)
15+
# bravo_x
16+
# charlie_x
17+
# (blank)
18+
#
19+
# Branch "delete-alpha" removes alpha_x (replaces with blank) and trailing blank.
20+
# Branch "delete-bravo" removes bravo_x.
21+
# These are non-overlapping edits that git merge-file resolves cleanly,
22+
# but Myers diff produces a false conflict.
23+
24+
git init
25+
26+
# Create the base content on main
27+
printf 'alpha_x\n\nbravo_x\ncharlie_x\n\n' > shared-file
28+
git add shared-file
29+
git commit -m "base: shared-file with alpha, bravo, charlie"
30+
31+
git branch gitbutler/workspace
32+
33+
# Branch A: delete alpha_x (replace with blank line) and remove trailing blank
34+
git checkout -b delete-alpha main
35+
printf '\n\nbravo_x\ncharlie_x\n' > shared-file
36+
git add shared-file
37+
git commit -m "delete alpha_x from shared-file"
38+
39+
# Branch B: delete bravo_x
40+
git checkout -b delete-bravo main
41+
printf 'alpha_x\n\ncharlie_x\n\n' > shared-file
42+
git add shared-file
43+
git commit -m "delete bravo_x from shared-file"

crates/but-workspace/tests/workspace/commit/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ mod move_commit;
66
mod reword;
77
mod uncommit_changes;
88

9+
mod myers_false_conflict;
10+
911
mod from_new_merge_with_metadata {
1012
use bstr::ByteSlice;
1113
use but_graph::init::{Options, Overlay};

0 commit comments

Comments
 (0)