Branching and Versioning |
![]() |
CDO history is easiest to understand as a coordinate system. A model object has a stable identity; its
modeled values are stored in successive revisions. A revision belongs to a branch, has a per-object integer version, and is valid for a time interval on that branch. A CDOBranchPoint
selects one branch and one time. A view reads the model at such a coordinate, while a transaction edits the current
state at the head of a branch.
This chapter explains the application-facing model of branches, branch points, revisions, historical views, and merges. Session-level branch and tag management is covered in Working with Sessions; view creation and lifecycle are covered in Working with Views; and transaction-side merge and revert operations are covered in Working with Transactions.
A CDO model object is the application-level object obtained from a resource in a view. Its CDOID is
its identity: the ID remains the same while the object changes, and an ID alone does not select a historical state.
Each committed state of that object is represented by a CDORevision. The revision carries the ID, branch,
version, creation timestamp, and revised timestamp, together with the modeled values.
A branch is a named stream of commits. The main branch is the root stream; a child branch starts at a fixed point in
its parent and then receives its own commits. A branch point is the pair of a branch and a time on that branch. A
timestamp identifies a historical point, while UNSPECIFIED_DATE identifies
the floating head of the branch. Consequently, "the current object" is shorthand for the object at a branch head,
not a branch-independent object.
A normal view can follow a branch head and update as new commits arrive. A historical view fixes its branch point and exposes the immutable state that was valid there. These coordinates are the important distinction: a version number is useful for one object's revision on one branch, but it is not a complete coordinate for a whole repository state.
Branches form a tree rooted at MAIN. A normal branch has a positive
technical ID; the main branch has ID 0. Branch names are mutable and are unique
among the direct children of their parent, not necessarily throughout the repository. Use a branch ID or the full
path returned by CDOBranch.getPathName() when a durable or unambiguous reference is needed.
A branch has a fixed base branch point in its parent and a floating
head. Creating a branch without a timestamp bases it at the current time; the overload
that accepts a timestamp lets an application branch from a selected historical point. A branch can be renamed with
CDOBranch.setName(String) and, where supported, deleted together with its sub-branches.
A branch point matters whenever code must name an exact repository state: it is used to open a historical view, request a revision, compare states, or describe the source or base of a merge. The head is intentionally floating; a historical point remains fixed even when later commits advance the branch.
For branch-manager lookup, enumeration, events, and deletion, see the Working with Sessions chapter.
CDOBranchVersion is the pair of a branch and an integer version. The version is assigned to one object's
successive revisions on that branch, beginning with 1. It is not a global
commit number, a timestamp, or a complete model version. Two revisions with the same integer version on different
branches are unrelated unless their branch coordinates also match.
The public API expresses the version value through getVersion() on CDORevision and
CDOVersionProvider; there is no independent repository-wide CDOVersion object. Use
CDOBranch.getVersion(int) when constructing a branch-version coordinate, and
org.eclipse.emf.cdo.common.revision.CDORevisionManager.Request.getRevisionByVersion(CDOID, CDOBranchVersion) when
an object must be loaded by that coordinate.
A CDORevision is immutable system information for one object between two commits. Its ID identifies the
object, its branch and version identify the revision in that branch, and its timestamps describe the interval in
which it is valid. Historical revisions report isHistorical(); a current revision
at a branch head has an unspecified revised time. A revision can be missing at a branch point because the object had
not yet been created, or because it was already detached there.
Open a read-only view at a branch, at a branch point, or at a timestamp on a branch with the corresponding
openView() overload. The concise branch-point form is
CDOViewContainer.openView(CDOBranchPoint). A view opened with CDOBranchPoint.UNSPECIFIED_DATE follows the
branch head; a view opened with a real timestamp is historical and remains at that time until its target is changed.
CDOView.setBranchPoint(CDOBranchPoint) can move a read-only view to another coordinate when the application
wants to browse history without creating another view.
Objects and resources obtained from a read-only view represent the selected state and cannot be mutated. Close the view when it is no longer needed. If a referenced object did not exist at the selected time, loading its revision can yield null and the corresponding historical graph does not contain that object. Historical inspection is therefore different from restoring data: use a transaction and the transaction APIs for an actual change.
For the complete view-type and lifecycle discussion, see Working with Views.
CDOObject.cdoHistory() and a view also provides commit
history for its objects. These histories describe commit metadata; they are not a replacement for loading the
object's revisions. Use the session's revision
manager with a branch point or branch version when the actual historical values are needed. This separation keeps
application code explicit about whether it needs commit metadata or model state.
To compare two states, first identify both with complete branch points and then use
CDOSession.compareRevisions(CDOBranchPoint, CDOBranchPoint) or
CDOView.compareRevisions(CDOBranchPoint). These APIs return CDOChangeSetData, which describes the
object-level changes between the selected states. They do not turn two model objects into a generic EMF comparison
editor, and a version number by itself is not enough to select either state.
For a single object, loading two revisions and calling
CDORevision.compare(CDORevision) provides a revision delta. For a repository-level comparison, prefer the
change-set APIs. The result is data for inspection or application to a transaction; it is not itself a commit and
it does not alter either historical state.
Open a transaction on a branch to edit that branch's head. Commits made by the transaction create new revisions on that branch and are isolated from the parent branch until an application explicitly merges changes. The transaction is always current-state/read-write; opening a historical read-only view is not a way to edit an old point.
A merge has a source state or source branch and a target transaction. CDO computes changes relative to a source base
and, where needed, a target base; the selected merger applies the
result to the target transaction. Conflicts belong to the transaction conflict model. Merge produces local changes,
so the application must resolve conflicts and commit the transaction before the target branch history changes.
The detailed merge overloads, conflict handling, and commit lifecycle are documented in Working with Transactions. This chapter supplies the branch-point vocabulary needed to choose source and base states.
Viewing an old branch point is read-only inspection. Reverting is a transaction operation that creates local changes intended to restore the transaction toward a historical branch point; it is not a deletion of repository history. Merging is different again: it applies changes from a source state into a target transaction. The resulting changes become repository history only after commit. See Revert for the operation-level distinction.
A tag is a named, movable reference to a branch point. Tags
are useful for naming releases or other meaningful historical coordinates, but they do not freeze a point when moved.
Branch and tag creation, lookup, and management belong to Branch Manager.
Branching is repository-dependent. Check CDOCommonRepository.isSupportingBranches() before relying on child
branches. The main branch exists in every repository mode, while sub-branches require branching support. Historical
views and tags depend on auditing support; check CDOCommonRepository.isSupportingAudits() when those features
are required. The repository's CDOCommonRepository.getMode() summarizes these capabilities.
Keep the branch and time (or branch and version for one object) explicit in history-sensitive code. Use branches for genuinely divergent model histories, historical views for read-only inspection, revision or change-set APIs for comparison, and transactions for merge or revert work. Do not treat an integer version as a repository-wide model version, and do not confuse a historical view with an operation that changes or rewrites repository history.