Skip to content

Add tests for Myers false-positive merge conflicts#13031

Draft
mtsgrd wants to merge 1 commit intomasterfrom
fix/myers-false-conflict-tests
Draft

Add tests for Myers false-positive merge conflicts#13031
mtsgrd wants to merge 1 commit intomasterfrom
fix/myers-false-conflict-tests

Conversation

@mtsgrd
Copy link
Copy Markdown
Contributor

@mtsgrd mtsgrd commented Mar 25, 2026

Adds test coverage for the gitoxide Myers diff bug ↗ in the context of workspace management. When two branches make non-overlapping edits to the same file, the Myers diff algorithm produces split hunks with empty insertions that falsely collide during the three-way merge — causing branches to be unapplied from the workspace.

Test results against unpatched gitoxide

Test Result Outcome
Basic merge of non-overlapping edits FAIL Second branch falsely unapplied
Hero stack with non-overlapping edits FAIL Hero preserved, non-hero falsely unapplied
Multi-commit branches FAIL Same false unapply — deeper history doesn't help
Squash then workspace merge FAIL Squash succeeds, but merge still falsely unapplies the other branch
Amend then workspace merge FAIL Amend succeeds, but merge still falsely unapplies the other branch
Stack ordering symmetry PASS Bug is symmetric — second stack always unapplied regardless of order

All five failing tests should pass once the upstream fix ( GitoxideLabs/gitoxide#2476 ↗ ) lands.

Test plan

  • Verify all 6 tests compile and run: cargo test -p but-workspace --test workspace myers_false_conflict
  • Confirm 5 expected failures against current gitoxide
  • Re-run after upgrading gitoxide to confirm all tests pass

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
gitbutler-web Ignored Ignored Preview Mar 28, 2026 1:54pm

Request Review

@github-actions github-actions bot added the rust Pull requests that update Rust code label Mar 25, 2026
@mtsgrd mtsgrd marked this pull request as ready for review March 25, 2026 10:46
Copilot AI review requested due to automatic review settings March 25, 2026 10:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds regression test coverage in but-workspace for a known gitoxide/gix Myers diff false-positive conflict that can cause otherwise independent stacks to be marked conflicting and unapplied during workspace merges.

Changes:

  • Add a new Rust test module covering several merge scenarios (basic, hero stack, multi-commit, squash, amend, ordering symmetry).
  • Add two new scenario fixtures to reproduce the problematic non-overlapping edits in a single file (single-commit and multi-commit variants).
  • Register the new test module in the workspace commit test suite.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
crates/but-workspace/tests/workspace/commit/myers_false_conflict.rs New regression tests exercising workspace merges that currently trigger Myers false conflicts.
crates/but-workspace/tests/workspace/commit/mod.rs Wires the new test module into the existing commit test suite.
crates/but-workspace/tests/fixtures/scenario/myers-false-conflict-same-file.sh New fixture repo reproducing non-overlapping edits in the same file.
crates/but-workspace/tests/fixtures/scenario/myers-false-conflict-multi-commit.sh New fixture repo reproducing the same issue with multi-commit branches for squash/amend cases.

@mtsgrd mtsgrd force-pushed the fix/myers-false-conflict-tests branch from f966237 to d582c07 Compare March 25, 2026 14:59
Copilot AI review requested due to automatic review settings March 25, 2026 15:08
@mtsgrd mtsgrd force-pushed the fix/myers-false-conflict-tests branch from d582c07 to c62de4c Compare March 25, 2026 15:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

// Verify the extra file is in the merged tree
let commit = merge_out.workspace_commit_id.attach(&repo).object()?;
let tree_viz = visualize_tree(commit.peel_to_tree()?.id());
insta::assert_snapshot!(tree_viz);
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insta::assert_snapshot!(tree_viz); will look for (or try to create) an external snapshot file under a snapshots/ directory. Since this PR doesn't add the corresponding .snap file, this test will fail in CI unless snapshots are updated. Consider switching to an inline snapshot (second argument) or add the generated snapshot file to the repo.

Suggested change
insta::assert_snapshot!(tree_viz);
assert!(
tree_viz.contains("extra-file.txt"),
"Merged tree should contain amended extra file, but got:\n{tree_viz}"
);

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +62
/// 1. A config file has three sections: `[alpha]`, `[bravo]`, `[charlie]`.
/// 2. User creates branch A and deletes the `[alpha]` section.
/// 3. User creates branch B and deletes the `[bravo]` section.
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reproduction comment describes sections like [alpha], [bravo], [charlie], but the actual fixture content and branch names use alpha_x, bravo_x, charlie_x. Aligning the comment with the fixture makes it easier to understand and maintain this test.

Suggested change
/// 1. A config file has three sections: `[alpha]`, `[bravo]`, `[charlie]`.
/// 2. User creates branch A and deletes the `[alpha]` section.
/// 3. User creates branch B and deletes the `[bravo]` section.
/// 1. A config file has three sections: `[alpha_x]`, `[bravo_x]`, `[charlie_x]`.
/// 2. User creates branch A and deletes the `[alpha_x]` section.
/// 3. User creates branch B and deletes the `[bravo_x]` section.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +54
mod utils {
use but_core::ref_metadata::{
StackId, WorkspaceCommitRelation::Merged, WorkspaceStack, WorkspaceStackBranch,
};
use but_meta::VirtualBranchesTomlMetadata;
use gix::refs::Category;

use crate::ref_info::with_workspace_commit::utils::{StackState, add_stack_with_segments};

pub fn add_stacks(
meta: &mut VirtualBranchesTomlMetadata,
short_stack_names: impl IntoIterator<Item = &'static str>,
) {
for (idx, stack_name) in short_stack_names.into_iter().enumerate() {
add_stack_with_segments(
meta,
idx as u128 + 1,
stack_name,
StackState::InWorkspace,
&[],
);
}
}

pub fn to_stacks(
short_stack_names: impl IntoIterator<Item = &'static str>,
) -> Vec<WorkspaceStack> {
short_stack_names
.into_iter()
.map(|short_name| WorkspaceStack {
id: StackId::generate(),
workspacecommit_relation: Merged,
branches: vec![WorkspaceStackBranch {
ref_name: Category::LocalBranch
.to_full_name(short_name)
.expect("known good short ref name"),
archived: false,
}],
})
.collect()
}
}
use utils::{add_stacks, to_stacks};

Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file defines a local mod utils with add_stacks/to_stacks that duplicates the helper module already present in crates/but-workspace/tests/workspace/commit/mod.rs (inside from_new_merge_with_metadata). Consider reusing a shared helper (or renaming to avoid divergence) so future changes don’t need to be made in multiple places.

Suggested change
mod utils {
use but_core::ref_metadata::{
StackId, WorkspaceCommitRelation::Merged, WorkspaceStack, WorkspaceStackBranch,
};
use but_meta::VirtualBranchesTomlMetadata;
use gix::refs::Category;
use crate::ref_info::with_workspace_commit::utils::{StackState, add_stack_with_segments};
pub fn add_stacks(
meta: &mut VirtualBranchesTomlMetadata,
short_stack_names: impl IntoIterator<Item = &'static str>,
) {
for (idx, stack_name) in short_stack_names.into_iter().enumerate() {
add_stack_with_segments(
meta,
idx as u128 + 1,
stack_name,
StackState::InWorkspace,
&[],
);
}
}
pub fn to_stacks(
short_stack_names: impl IntoIterator<Item = &'static str>,
) -> Vec<WorkspaceStack> {
short_stack_names
.into_iter()
.map(|short_name| WorkspaceStack {
id: StackId::generate(),
workspacecommit_relation: Merged,
branches: vec![WorkspaceStackBranch {
ref_name: Category::LocalBranch
.to_full_name(short_name)
.expect("known good short ref name"),
archived: false,
}],
})
.collect()
}
}
use utils::{add_stacks, to_stacks};
use super::from_new_merge_with_metadata::utils::{add_stacks, to_stacks};

Copilot uses AI. Check for mistakes.
@Caleb-T-Owens
Copy link
Copy Markdown
Contributor

Caleb-T-Owens commented Mar 25, 2026

Hey! I'm curious if you could elaborate on why your interested in testing at this particular place and level

@mtsgrd mtsgrd marked this pull request as draft March 25, 2026 16:45
@mtsgrd
Copy link
Copy Markdown
Contributor Author

mtsgrd commented Mar 25, 2026

Hey sorry, I should have put this in draft. It's related to GitoxideLabs/gitoxide#2476, I'm trying to figure out how I got myself into a position to discover that problem in the first place.

It's half baked atm, and I'm omw to dinner now.. but I should have some conclusion from these test cases by tomorrow.

@mtsgrd mtsgrd force-pushed the fix/myers-false-conflict-tests branch from c62de4c to a8f6a7f Compare March 28, 2026 13:44
Add test fixtures and 7 workspace-level tests that reproduce the
gitoxide Myers diff bug where non-overlapping edits to the same file
are falsely reported as conflicts. The tests cover single-file edits,
multi-commit branches, amend-then-merge, and squash-then-merge
scenarios. Five tests fail as expected, documenting the bug until
the upstream fix (gitoxide#2476) lands.
@mtsgrd mtsgrd force-pushed the fix/myers-false-conflict-tests branch from a8f6a7f to f318f28 Compare March 28, 2026 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants