Skip to main content

Revision history and merge base

Every version of a project is a revision in a history graph. A revision can have up to two parents, which is what makes the history a graph rather than a list. Apiome answers two questions about that graph: which revisions came before a given one (its ancestors), and where two lines of history last met (their merge base). The branch, merge and history-graph tools in Version dialogs are built on these.

A revision…ParentsExample
created on its ownnone — it is a rootThe first version of a project, a version created from New version, an import
that continues a line of historyone, the first parentA repository refresh, a revision on a branch
that merges two branchestwo: the first parent and the merge parentThe result of Merge branches…
forked from another projectnone in this projectA fork records where it came from separately, and starts a new root

A revision with no parent is a root on purpose, not missing data. Versions created before branch and merge support existed, and versions created on their own today, are roots: the history graph shows them unconnected, and two of them have no merge base.

Ancestors​

The ancestors of a revision are every revision reachable by following parents, both parents of a merge included. Each one comes with its distance: the fewest parent steps from the revision you started at (that revision itself is 0).

A history window is the same walk from several starting revisions at once, such as every branch tip, cut off after a number of steps. It is what the history graph draws: one request returns every revision in the window with both of its parent ids, so the graph never asks for revisions one by one.

Merge base​

The merge base of two revisions is their best common ancestor: a revision both histories contain that is not an ancestor of another such revision. It is where the two lines of history split, and it is the "base" side of a three-way merge.

  • When one revision is an ancestor of the other, the merge base is the older one.
  • When the histories share no revision — two separate roots — there is no merge base, and a merge between them cannot be previewed.
  • When two branches have merged into each other (a criss-cross history), there can be more than one best common ancestor. All of them are listed, and the most recently created one is the merge base.

With the API​

RequestReturns
GET /v1/versions/{tenant}/{project}/{revision}/ancestors?depth=50&limit=500The revision and its ancestors within depth parent steps
GET /v1/versions/{tenant}/{project}/revision-graph/history?tip=…&tip=…&depth=50&limit=500A history window from the named tips — every branch tip when tip is left out
GET /v1/versions/{tenant}/{project}/revision-graph/merge-base?a=…&b=…The merge base of two revisions, every candidate, and whether the histories are disjoint

Each revision in a window has revisionId, versionLabel, parentRevisionId, mergeParentRevisionId, createdAt and distance. Revisions are ordered nearest the tips first, then newest first. The full request and response shapes are in the REST reference.

Limits​

SettingDefaultMaximum
depth — parent steps from the tips501,000
limit — revisions returned5005,000
tip — starting revisions per requestevery branch tip50

When the depth or the limit cuts the history short, the response says "truncated": true; ask again from the oldest revisions you received to page further back. Every request reads the history in a single database query, however many revisions it covers.

Error codeCause
REVISION_NOT_FOUND (404)A named revision does not exist, or was deleted
REVISION_PROJECT_MISMATCH (400)A named revision belongs to a different project
TIPS_REQUIRED (400)No tip was given and the project has no branches
TOO_MANY_TIPS (400)More than 50 tips