Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions pr_split/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,14 +289,20 @@ def _stacked_batch_args(
merge_base_ref: str,
hunk_counts: dict[str, int],
) -> Generator[list[tuple[Group, str, str]], None, None]:
effective: dict[str, Group] = {}
for batch in dag.iter_ready():
batch_args: list[tuple[Group, str, str]] = []
for gid in batch:
group = groups_by_id[gid]
parents = dag.parents(gid)
if len(parents) == 1:
merged = merge_chain_assignments(group, [effective[parents[0]]], hunk_counts)
# Files are rebuilt from the merge base, so a child must carry
# every ancestor's hunks for the files it touches - not only
# its direct parent's - or it silently reverts them.
merged = merge_chain_assignments(
group,
[groups_by_id[a] for a in sorted(dag.ancestors(gid))],
hunk_counts,
)
start_point = branch_names[parents[0]]
group_base = branch_names[parents[0]]
elif len(parents) > 1:
Expand All @@ -315,7 +321,6 @@ def _stacked_batch_args(
merged = group
start_point = merge_base_ref
group_base = base_branch
effective[gid] = merged
batch_args.append((merged, group_base, start_point))
yield batch_args

Expand Down
43 changes: 43 additions & 0 deletions tests/test_cli_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,49 @@ def _merge_node_args(self) -> tuple[Group, str, str]:
if merged.id == "pr-3"
)

def test_grandchild_carries_grandparent_hunks_in_shared_file(self) -> None:
# A edits f.py hunk 0; B (child of A) edits only g.py; C (child of B)
# edits f.py hunk 1. C is rebuilt from the merge base, so it must
# carry A's hunk 0 or its commit reverts A's change.
a = _group("pr-a", "a")
a.assignments = [
GroupAssignment(
file_path="f.py",
assignment_type=AssignmentType.PARTIAL_HUNKS,
hunk_indices=[0],
)
]
b = _group("pr-b", "b", ["pr-a"])
b.assignments = [
GroupAssignment(
file_path="g.py",
assignment_type=AssignmentType.PARTIAL_HUNKS,
hunk_indices=[0],
)
]
c = _group("pr-c", "c", ["pr-b"])
c.assignments = [
GroupAssignment(
file_path="f.py",
assignment_type=AssignmentType.PARTIAL_HUNKS,
hunk_indices=[1],
)
]
groups = [a, b, c]
batches = _stacked_batch_args(
PlanDAG(groups),
{g.id: g for g in groups},
{g.id: f"pr-split/ns/{g.id}" for g in groups},
"main",
"base_sha",
{"f.py": 2, "g.py": 1},
)
merged_c, base, start = next(
(m, bs, st) for batch in batches for m, bs, st in batch if m.id == "pr-c"
)
assert {a.file_path: a.hunk_indices for a in merged_c.assignments} == {"f.py": [0, 1]}
assert (base, start) == ("pr-split/ns/pr-b", "pr-split/ns/pr-b")

def test_merge_node_carries_both_parents_changes(self) -> None:
merged, _, _ = self._merge_node_args()
assert {a.file_path for a in merged.assignments} == {
Expand Down
Loading