Merging models
bluep merges models at the model level, not line by line. Two people who edit different entities, or
different attributes of the same entity, merge cleanly even when a text merge would report overlapping hunks.
Only a field changed to two different values on both sides is a conflict.
Directory merge
bluep merge <base_dir> <ours_dir> <theirs_dir> --out <dir> [--prefer ours|theirs] [--json]
base_dir is the common ancestor, ours_dir your version, theirs_dir the other version. The merged model
is written to <dir> in canonical form, even when there are conflicts. Each object keeps the file it has in
ours (or in theirs for objects only theirs has).
Exit code 0 means a clean merge. Exit code 1 means conflicts; they are printed one per line:
CONFLICT entities.order.description: base "An order." | ours "Orders placed by customers." | theirs "A customer order."
The path is the position in the JSON form of the model (bluep export json). - marks a value that is absent
on one side (added or deleted). A conflict is resolved in the output with the ours value, or with theirs
when --prefer theirs is given; review the output and edit it. --json prints the conflicts as a JSON array
of {"path", "base", "ours", "theirs"} objects instead of the text lines.
If the merged model does not validate (for example one side deleted an entity that the other side started
to reference), each validation issue is reported as a conflict with path validate.
Merge rules
At every node of the model, in this order:
- Both sides equal: take it.
- Only one side changed: take the changed side.
- Both are objects (entities, columns of a schema, ...): merge key by key. A key deleted on one side and untouched on the other is deleted; deleted on one side and changed on the other is a conflict.
- Lists of named items (attributes, columns, partitions): merged by name. The base order is kept; items
added by
oursare inserted after their predecessor inours, then items added bytheirslikewise. - Sets of names (
tags,terms, areaentities,aliases,forbidden, triggerevents, propertyapplies, rolemember_of, grantprivileges, triggerupdate_columns): additions from both sides are kept, deletions from either side are applied. - Anything else that differs on both sides is a conflict.
Git merge driver
bluep merge-file <base> <ours> <theirs> [--prefer ours|theirs]
merges one .bluep file, writes the canonical result over <ours> and prints conflicts to stderr. The file
may be a subject-area or schema file without a model declaration. To let git use it:
git config merge.bluep.name "bluep model merge"
git config merge.bluep.driver "bluep merge-file %O %A %B"
and in .gitattributes at the repository root:
*.bluep merge=bluep
With the driver configured, git merge, git rebase and git cherry-pick call bluep for every .bluep file
changed on both sides. A clean merge stages the file; conflicts leave the file in the working tree with the
ours values and the conflict lines on the terminal, so git status shows it as unmerged until you fix and
git add it. The result is always canonical, so bluep fmt reports no changes afterwards.
Notations and stereotypes
Diagrams are drawn in crow's-foot notation by default. notation idef1x in the model block switches the
whole model to IDEF1X; notation crows_foot or notation idef1x in an area block overrides it for that
area's diagram. In IDEF1X, identifying relationships are solid lines and non-identifying ones dashed, the
child end carries a filled circle, an optional parent a hollow diamond, and the child cardinality is marked
P (one or many), Z (zero or one) or 1 (exactly one). Entities that are children of an identifying
relationship are drawn with rounded corners and primary-key attributes sit above a separator line.
stereotype fact, stereotype dimension or stereotype bridge in an entity block colours the entity
header in diagrams, shows the role in the data dictionary and enables the lint rule dimensional-star when
switched on in the lint block: a fact may only reference dimensions and bridges, and every dimension needs a
single-column integer surrogate key.