Branching and Versioning

 

Author: Eike Stepper

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.

1 Mental Model
2 Branches and Branch Points
3 Versions and Revisions
4 Historical Views and Navigating History
4.1 An object's commit history is available through
5 Comparing Historical State
6 Branching, Transactions, and Merge Concepts
7 Revert, Tags, and Repository Capability
8 Practical Guidance

1  Mental Model

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.

2  Branches and Branch Points

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.

3  Versions and Revisions

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.

4  Historical Views and Navigating History

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.

4.1  An object's commit history is available through

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.

5  Comparing Historical 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.

6  Branching, Transactions, and Merge Concepts

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.

7  Revert, Tags, and Repository Capability

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.

8  Practical Guidance

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.