Concepts
Oxygen has a handful of ideas. Everything else follows from them.
classDiagram
direction LR
class Change {
ChangeId: stable, random
ChangeHash: content hash
deps: earlier changes it builds on
tree_ops and edits
author, message, time
}
class State {
heads: the newest changes
= heads + everything they depend on
}
class Bookmark {
name
points at a state
}
class Tag {
name
immutable, signed
}
class Operation {
command
view: every bookmark and workspace
}
Change "many" --o State : a state is a set of changes
Bookmark --> State
Tag --> State
Operation --> Bookmark : records
Changes, not snapshots
Git stores a snapshot of the whole tree in every commit and links commits in a chain. Oxygen stores changes: each records what it did to specific lines and files, and which earlier changes it builds on.
flowchart LR
subgraph Git[Git: a chain of snapshots]
direction LR
g1[snapshot 1] --> g2[snapshot 2] --> g3[snapshot 3] --> g4[merge commit]
g2 --> g5[snapshot 3b] --> g4
end
subgraph Oxygen[Oxygen: a set of changes]
direction LR
c1[add parser.rs]
c2[fix parser.rs] --> c1
c3[add README]
c4[edit README] --> c3
end
In Oxygen, the two edits on the right never needed each other, so they have no order and no merge between them. This is what commutation means: see Changes and Dependencies.
Two names for every change
| Name | Looks like | Stays the same when... | Used for |
|---|---|---|---|
| ChangeId | 658990aa | you reword, amend or rebase the change | what you type, what tools track |
| ChangeHash | #7469d16c | nothing: any edit makes a new hash | integrity: every reference between objects uses it |
Rewriting a change makes a new object with the same ChangeId and a new hash. If two different changes with one ChangeId are both reachable, Oxygen calls it divergence and tells you, rather than guessing.
States and heads
A state is a set of changes that includes everything its members depend on. It is named by its heads, the changes nothing else in the set depends on.
flowchart BT
A[A]
B[B] --> A
C[C] --> A
D[D] --> B
style D fill:#cde,stroke:#357
style C fill:#cde,stroke:#357
The state {A, B, C, D} has two heads, C and D (shaded). Several heads are normal: every independent change is a head until something builds on it. It is not a conflict.
Bookmarks and tags
- A bookmark is a named, movable pointer to a state, like a Git branch.
- A tag is a named, signed pointer to a state that never moves.
Atoms: every line has an identity
Inside a text file, each line is an atom with an identity: the change that introduced it and its position in that change. Edits say "insert these lines between atom X and atom Y" or "delete atoms X..Y", never "at line 42". That is why changes can be applied in any order and still give the same file. See Changes and Dependencies.
Files and directories have identities too (NodeIds), so a rename is a move of the same node and history follows it exactly.
The working copy is a change
There is no staging area. The files in your directory are always described by a special working-copy change, which oxy updates before each command. oxy commit gives it a message and starts a fresh one on top. See Working Copy and Operation Log.
Everything is an object
Changes, states, identities, attestations and file content are all objects: immutable byte strings named by their BLAKE3 hash. Change one byte and the name changes, so a tampered object cannot pass as the original. See Storage.