Fix local-priority merge to avoid remote reorders in conflicts
This commit is contained in:
+28
-15
@@ -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 = {
|
||||||
|
|||||||
Reference in New Issue
Block a user