graflo.architecture.evolution.merge_commit¶
Recording a merge as a commit.
Deliberately not in merge.py. That module is the pure algorithm: two
manifests in, one out, no notion of a store or of history. Stamping and
recording are what a commit point does to the result afterwards -- the same
separation contract/provenance.py draws to keep provenance out of
apply_evolution, and for the same reason. A merge that recorded its own
lineage could not be run twice without inventing two different histories.
A merge commit is materialized exactly as a merge commit is: its ops are the
verified diff from its first parent, so first-parent replay and hash
verification need no special case anywhere downstream. What makes it a merge
rather than a merge is the declaration that rides alongside it -- a
:class:~graflo.architecture.evolution.merge3.MergeRecipe of kind merge,
which is what a re-merge reads.
Attributes¶
__all__ = ['build_merge_commit', 'find_commit_by_tree']
module-attribute
¶
Classes¶
Functions:¶
build_merge_commit(left, merged, *, parents, recipe, right=None, label=None, created_at=None, notes=None)
¶
Record merged as a merge commit over parents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
GraphManifest
|
The first parent's manifest -- the side the ops are diffed from. |
required |
merged
|
GraphManifest
|
The merge result. |
required |
parents
|
list[str]
|
Parent commit ids, first parent first (at least two). |
required |
recipe
|
MergeRecipe
|
The recorded declaration, so a re-merge can replay it. |
required |
right
|
GraphManifest | None
|
The second input. When given, the relabel the merge applied to
left is recorded ahead of the diff (see :func: |
None
|
label
|
str | None
|
Short human-readable name. |
None
|
created_at
|
str | None
|
ISO-8601 timestamp. |
None
|
notes
|
str | None
|
Free-form annotation. |
None
|
Raises:
| Type | Description |
|---|---|
CommitError
|
Fewer than two parents, or the derived diff does not reproduce merged -- which happens when the two sides differ somewhere no op reaches. |
Source code in graflo/architecture/evolution/merge_commit.py
find_commit_by_tree(history, manifest)
¶
The commit whose recorded tree is this manifest's content address.
How a file path becomes a commit id without the caller naming one: a manifest is its content hash, and a commit records the tree it produced, so the two meet without any extra bookkeeping.
More than one commit can legitimately reach one tree -- two routes to the same world model are the case content addressing exists to recognise. When that happens a head wins, because that is the state someone is working from; failing that the lowest id, so the answer never depends on store order.
Source code in graflo/architecture/evolution/merge_commit.py
left_relabel_ops(left, right, recipe)
¶
The relabel a merge applied to its left side, as ops.
merge_manifests resolves its declared clusters and canonical maps into
one composite canonicalize per side and applies it before the union.
The left one is part of how the merged manifest came from the left, so a
merge commit records it first. Resolved from the recorded declaration --
the whole op, canonical maps included -- against both sides, exactly as
the merge resolved it.