Add tests for Myers false-positive merge conflicts#13031
Add tests for Myers false-positive merge conflicts#13031
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
There was a problem hiding this comment.
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. |
crates/but-workspace/tests/workspace/commit/myers_false_conflict.rs
Outdated
Show resolved
Hide resolved
crates/but-workspace/tests/workspace/commit/myers_false_conflict.rs
Outdated
Show resolved
Hide resolved
crates/but-workspace/tests/workspace/commit/myers_false_conflict.rs
Outdated
Show resolved
Hide resolved
f966237 to
d582c07
Compare
d582c07 to
c62de4c
Compare
| // 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); |
There was a problem hiding this comment.
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.
| insta::assert_snapshot!(tree_viz); | |
| assert!( | |
| tree_viz.contains("extra-file.txt"), | |
| "Merged tree should contain amended extra file, but got:\n{tree_viz}" | |
| ); |
| /// 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. |
There was a problem hiding this comment.
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.
| /// 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. |
| 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}; | ||
|
|
There was a problem hiding this comment.
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.
| 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}; |
|
Hey! I'm curious if you could elaborate on why your interested in testing at this particular place and level |
|
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. |
c62de4c to
a8f6a7f
Compare
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.
a8f6a7f to
f318f28
Compare
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
All five failing tests should pass once the upstream fix ( GitoxideLabs/gitoxide#2476 ↗ ) lands.
Test plan
cargo test -p but-workspace --test workspace myers_false_conflict