Fix local-priority merge to avoid remote reorders in conflicts

This commit is contained in:
Koha9
2025-11-25 10:08:42 +09:00
parent a912213e2e
commit 97aa598775
+28 -15
View File
@@ -76,6 +76,7 @@ class MergeChunk:
base_text: str | None = None base_text: str | None = None
local_text: str | None = None local_text: str | None = None
remote_text: str | None = None remote_text: str | None = None
origin: str | None = None
@dataclass @dataclass
@@ -126,15 +127,25 @@ def _normalize_inputs(
def _merge_chunks( def _merge_chunks(
base_paths: Sequence[str], local_paths: Sequence[str], remote_paths: Sequence[str] base_paths: Sequence[str], local_paths: Sequence[str], remote_paths: Sequence[str]
) -> list[MergeChunk]: ) -> list[MergeChunk]:
"""Run a diff3 merge on normalized playlists and return merge chunks."""
merger = Merge3(base_paths, local_paths, remote_paths) merger = Merge3(base_paths, local_paths, remote_paths)
raw_chunks = list(merger.merge_groups())
chunks: list[MergeChunk] = [] chunks: list[MergeChunk] = []
for group in merger.merge_groups(): for kind, *payload in raw_chunks:
kind = group[0]
if kind == "conflict": if kind == "conflict":
base_lines, local_lines, remote_lines = group[1], group[2], group[3] base_lines, local_lines, remote_lines = payload # type: ignore[misc]
# Absorb trailing side-only chunks that actually belong to this
# conflicting region (common in reorder scenarios).
while chunks and chunks[-1].origin in ("a", "b"):
previous = chunks.pop()
previous_lines = previous.text.splitlines() if previous.text else []
if previous.origin == "a":
local_lines = previous_lines + local_lines
else:
remote_lines = previous_lines + remote_lines
chunks.append( chunks.append(
MergeChunk( MergeChunk(
type="conflict", type="conflict",
@@ -144,16 +155,11 @@ def _merge_chunks(
) )
) )
else: else:
if kind in ("unchanged", "same", "a", "b"): lines = payload[0]
lines = group[1] if not lines:
chunks.append( continue
MergeChunk( chunk = MergeChunk(type="normal", text=playlist_to_text(lines), origin=kind)
type="normal", chunks.append(chunk)
text=playlist_to_text(lines),
)
)
else:
raise ValueError(f"Unsupported merge chunk type: {kind}")
return chunks return chunks
@@ -213,12 +219,19 @@ def merge_playlists(
) )
chunks = _merge_chunks(base_paths, local_paths, remote_paths) chunks = _merge_chunks(base_paths, local_paths, remote_paths)
has_conflict = any(chunk.type == "conflict" for chunk in chunks)
merged_lines: list[str] = [] merged_lines: list[str] = []
conflicts: list[dict] = [] conflicts: list[dict] = []
for chunk in chunks: for chunk in chunks:
if chunk.type == "normal": if chunk.type == "normal":
if (
strategy == ConflictResolutionStrategy.LOCAL_PRIORITY
and has_conflict
and chunk.origin == "b"
):
continue
merged_lines.extend(chunk.text.splitlines()) merged_lines.extend(chunk.text.splitlines())
else: else:
conflict_info = { conflict_info = {