Versions, branches and reviews#
A project file (.ohl) keeps its own version history, like source code in
git (DESIGN_GOALS §7, ADR-0010):
- a revision records the line and its library files as they are, with author, time and a message ("Raised T12 by 3 m for the road crossing");
- branches hold design alternatives and what-if scenarios;
mainis the first; - tags name revisions for good ("IFC rev B — issued for construction");
- diff shows what changed between two revisions, object by object and field by field, and its engineering impact (sags, tensions, clearances of the sections touched);
- merge brings a branch back, object by object and field by field; conflicting changes are listed and settled one by one;
- revert makes a revision undoing another's changes.
The operation log (ohl project log, Versions › History) still records every
command; revisions are the named states between them.
The working state#
Every branch is a project line with a working state of its own
(see Project lines and phases): what you edit is the
working state of the line you work on. Commands change it as before (each
logged, undoable per user and per line). A commit records it as a
revision of that branch. Check out chooses the line you work on: nothing
changes, uncommitted work stays on its line. A tag or revision is not worked
on directly: make a line from it (branch NAME --at TAG). In the desktop
app, the line you work on is chosen per user (Versions › Project lines); on
the command line, checkout also sets the line the file opens on.
In server mode every user works on their own line; a merge changes the line it merges into, for everyone who works on or shows that line.
Not under version control: point clouds, terrain surfaces, project settings, users and the operation log.
On the command line#
ohl project status project.ohl # branch, uncommitted changes
ohl project commit project.ohl --user ana -m "as imported"
ohl project branch project.ohl "route B" --user ben # a new line: a copy of the current one
ohl project checkout project.ohl "route B" --user ben
ohl project apply project.ohl --user ben '{"op": "move_structure", "id": "T6", "position": [1500, 400, 505]}'
ohl project diff project.ohl # HEAD → working state, field by field
ohl project diff project.ohl --impact # … and the sections solved on both sides
ohl project commit project.ohl --user ben -m "T6 east of the road"
ohl project history project.ohl # revisions with branches and tags (--limit, default 50)
ohl project checkout project.ohl main --user ana
ohl project merge project.ohl "route B" --user ana --preview
ohl project merge project.ohl "route B" --user ana
ohl project tag project.ohl "IFC rev A" --user ana --note "issued for construction"
ohl project revert project.ohl 3f2a9c1e --user ana # a new revision undoing 3f2a9c1e
ohl project branch project.ohl # list branches and tags
Revisions are named by a branch, a tag, HEAD, or the start of their id
(at least 4 characters).
diff FROM TO compares two revisions; without TO the working state;
without either, the head and the working state. --brief lists the objects
only.
Engineering impact#
ohl project diff … --impact solves every section the change touches —
changed sections, sections through changed structures, every section when a
library file changed — on both sides, each with its own libraries, and
lists per section the largest sag, the largest tension and the smallest
vertical clearance to the ground, for example:
engineering impact in "15 °C" (1 sections in 25.7ms, ground: surface DTM):
section max sag, m max tension, kN min clearance, m
S3 6.86 → 7.02 (+0.16) 22.15 → 21.90 (-0.25) 11.40 → 11.12 (-0.28)
The weather case: --weather FILE [--case NAME], or still air at
--temperature (15 °C). The ground: --surface NAME, default the surface of
the checks. Wires missing in a state come from --library (default: the
shipped libraries). Limits: --max-sections (500) and --time-limit
(60 s); what is left is reported as not solved.
Merging and conflicts#
merge merges another branch into the current one, against their nearest
common ancestor:
- an object changed on one side only is taken from that side;
- an object changed on both sides is merged field by field (one side moved T6, the other turned it: both are kept);
- a field changed differently on both sides, or an object deleted on one side and changed on the other, is a conflict.
Conflicts are listed with their key, the common value and both sides; the merge is refused until each one is settled:
$ ohl project merge project.ohl "route B" --user ana
route B (fbf339818a): three-way merge, common ancestor d249e078b6
conflict structure:T6/position: base [640.0,280.0,504.0], ours [1490.0,400.0,505.0], theirs [1500.0,400.0,505.0]
error: refused: 1 conflict(s) to settle (choose ours or theirs for each): structure:T6/position
$ ohl project merge project.ohl "route B" --user ana --choose structure:T6=theirs
--choose KEY=ours|theirs settles one conflict; an object's key
(structure:T6) settles all its fields; library files have keys
library:cables/acsr.ohlw. The merged line must be valid like after any
command (a section cannot run through a structure the other side deleted);
otherwise the merge is refused with the reason. A branch with nothing new
of its own is simply moved forward (fast-forward). The merge is one logged
command in the working state and a revision with two parents.
revert works the same way: the changes of one revision are taken out of
the working state; changes made to the same fields since are conflicts.
Branches and tags#
ohl project branch project.ohl NAME --user U [--at REV] makes a branch;
--protect (admins) protects it and --unprotect lifts that: a protected branch is changed only by
admins or by merging an approved review. --delete lists what goes with the
branch (open reviews closed; revisions only on it stay in the file, reachable
by id) and deletes it with --confirm. Tags are made with ohl project tag
and deleted by admins (--delete --confirm).
Reviews#
ohl project branch project.ohl main --user ana --protect # admins only
ohl project review project.ohl --user ben --submit "route B" --into main --reviewer rita --note "T6 moved for the road"
ohl project review project.ohl # list
ohl project review project.ohl --user rita --reject 1 --note "too close to the road"
ohl project review project.ohl --user ben --submit "route B" --reviewer rita # changed, submitted again
ohl project review project.ohl --user rita --approve 2 --note "fine"
ohl project review project.ohl --user rita --merge 2 # into main, whatever line rita works on
Reviewers named in the review (not its author) and admins approve or reject. An approved review is merged by a reviewer or an admin, also into a protected branch; a branch changed after its approval must be submitted again.
Who may edit what#
Admins limit what a user — or every user of a role — may edit:
ohl project grant project.ohl --by ana --subject ben --kind structure --kind section --area "500,-100;900,-100;900,300;500,300"
ohl project grant project.ohl --by ana --subject role:designer --object T12 --object T13
ohl project grant project.ohl # list
ohl project grant project.ohl --by ana --revoke 2
A grant names kinds (structure, section, jumper, route, meta for
the line settings, library for library files), objects (T12 or
structure:T12) and/or a plan area (a polygon, project coordinates). A user
with grants may change only what one of them covers — every object a command
changes, also what a deletion takes along, before and after the change (an
object's plan bounds must lie inside the area). Users without grants edit
what their role allows; admins are never limited. The session checks every
command, so a server refuses the same. Users with grants cannot merge,
bring in changes or revert, which replace the working state at large.
Offline work#
A copy of the project file (copied while it is closed, or the copy a client joining a server receives) shares the revision ids of the original. Work offline on a branch in the copy, commit, and carry the branch back:
ohl project bundle copy.ohl --export field --out field.json # in the copy
ohl project bundle project.ohl --import field.json --user ben # in the project
ohl project merge project.ohl field --user ana
The bundle holds the branch's revisions and their contents (--as NAME imports it under another branch name); ids and hashes
are checked when it is read. Not yet: synchronising automatically when the
copy reconnects.
In the desktop app#
Versions › Revisions and branches… opens the version window:
- History: the revisions newest first (◆ a merge), with their branches and tags; Commit with a message; branches with Work on it (the project line you edit), protect (admins) and Delete… (lists what goes first); per revision Diff, Tag…, New line from it and Revert.
- Changes: two revisions (or a revision and the working state) compared field by field; Engineering impact solves the touched sections in the weather case shown, on the surface of the checks.
- Merge: Preview lists what the merge does and its conflicts, each with ours / theirs; Merge when all are settled.
- Reviews: submit a branch, approve or reject with a comment, merge an approved one.
- Rights (admins): grants listed, revoked, made.
Each project line has its own library files (a new line starts with those of the line it is made from): a library changed on one line leaves the others as they are, and a library change is undone like any other. When a merge or a change of line brings other library files, they are read again.