mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
Merge engine: a same-parent reorder, an addition under a parent main deleted, and a branch deleting a container main edited each lost work silently. Each now follows a policy read from backend/resources/app/branch-merge-policies.edn, re-read when the file changes, with the defaults: merge the reorder, and raise a conflict on the deleted parent or container. Added siblings keep the branch's order. A :mov-page index counts the target's full page list, a cleared page background reaches main, a per-attribute resolution can remove an attribute, and a token set reorder survives a rename on the other side. Conflict payloads name :main and :branch by document in both directions. Reorder detection costs nothing measurable on a page of 20,201 objects. Data versions: each op-log row records the data version it was written at, the branch replays its log in segments and migrates the document at each boundary, and the comparison base is migrated like main and the branch, so an upgrade no longer shows as false conflicts. Writers: a binfile import, an admin repair, file GC and a snapshot restore refuse a branch file, whose payload nothing reads, and the branch base pin cannot be renamed into a user snapshot. A branch save runs the ordinary media fix-up and logs the rewritten references. An update from main deletes the branch's copy of media main deleted and squashes no phantom media changes. Commands and UI: the pull-request commands publish their messages after the commit, the listing takes one connection per comparison and shows a warning instead of "in sync" when a comparison fails, materialize takes :branch-file-id, and a dashboard fetch that never answers ends in an error state instead of a spinner, with a refetch on reconnect. backend/dev/branch_merge_cases.clj builds one example file per merge policy case for demonstrating the alternatives. Two models wrote this change, claude-opus-5-5 and mimo-v2.6-pro, and the work switched between them, so the trailer reads mixed models. AI-assisted-by: mixed models