ee06a6c5 Andy McCall 1 month ago ↶
1
# Oxygen user guide
2
3
This guide is organised by task. It assumes the ` oxy` binary is on your
4
path (` cargo build --release` puts it in ` target/release/` ). The design
5
behind every command is in [ spec.md ] ( spec.md ) ; this guide only tells you
6
what to type and what to expect.
7
8
Oxygen tracks * changes* rather than snapshots: a change is the set of
9
edits you made, it commutes with unrelated changes, and conflicts are
10
recorded in history instead of blocking you. Two ideas recur below:
11
12
- A ** bookmark** (default ` main` ) names a * state* : the set of changes it
13
contains. A state can have several ** heads** when independent changes
14
have not been related to each other; that is normal, not a problem.
15
- The ** working copy** is itself a change that Oxygen rewrites every time
16
it looks at your files. ` oxy commit` turns it into a real change.
17
18
Output uses colour and glyphs on a terminal; pipe it, pass ` --plain` , or set
19
` NO_COLOR` for plain ASCII.
20
21
## 1. Set yourself up
22
23
```
24
oxy identity create --name "Ada Lovelace" --email [email protected]
25
oxy config --user core.sign change
26
```
27
28
` identity create` generates a composite Ed25519 + ML-DSA-65 key pair, keeps
29
the secret in ` ~/.config/oxy/keys/` , and records you as the default author
30
in ` ~/.config/oxy/config.toml` . With ` core.sign = change` every commit is
31
signed; without it, changes are sealed in batches when you push (also
32
authenticated, just later). Use ` --local` to record the identity in one
33
repository only.
34
35
` oxy identity show` prints the key, its expiry, delegates, and whether the
36
secret is available. ` oxy identity export` writes the public identity to a
37
file to hand to whoever manages a trust policy (section 8).
38
39
## 2. Start a repository
40
41
```
42
mkdir project && cd project
43
oxy init
44
oxy status
45
```
46
9ac1fbe2 Andy McCall 1 month ago ↶
47
` oxy init` creates ` .oxy/` . Add ` .oxyignore` (gitignore syntax, per
48
directory, negations with ` !` ) for files that should never be tracked;
49
` /target` and ` *.tmp` are typical entries. As in Git, ignore rules only
50
affect untracked files: a file already in history stays tracked until you
d4dbab97 Andy McCall 1 month ago ↶
51
delete it. A project's ` .gitignore` files are honoured too, so moving a Git
52
project to Oxygen does not commit its build output; ` .oxyignore` comes
53
first, and a ` !` rule there brings back what ` .gitignore` leaves out.
ee06a6c5 Andy McCall 1 month ago ↶
54
55
To take over an existing Git project, see section 12.
56
57
## 3. Everyday work
58
59
```
60
oxy status # what changed since the last commit
61
oxy diff # the edits, file by file
62
oxy commit -m "Add retry loop"
63
oxy log # newest first; -n 10, -v for full messages
47ce8b8e Andy McCall 1 month ago ↶
64
oxy log -r 'main.. & touches("src/**")' # a revset (docs/revset_query_language.md)
ee06a6c5 Andy McCall 1 month ago ↶
65
oxy show 658990aa # one change by ChangeId prefix, #hash prefix, or @
66
```
67
2bf22305 Andy McCall 1 month ago ↶
68
` oxy log` draws the history as a graph, newest first, two lines per change:
69
70
```
71
◉ 2f8518c0 Andy McCall just now
33472ccc Andy McCall 1 month ago ↶
72
│ (working copy)
2bf22305 Andy McCall 1 month ago ↶
73
● 1b5888b1 Andy McCall 2 minutes ago main #cc23b999 ✔ signed
74
│ Edit b
75
│ ● d6f52eca Andy McCall 3 minutes ago main #ec6a7dc4 ✔ signed
76
├─╯ Edit a
77
○ c0593116 Andy McCall 5 minutes ago #eeac7940 ✔ signed
78
Both files
79
```
80
81
The bright start of each ID is the shortest prefix that names it. ` ●` marks
82
a head, ` ◉` the working copy. Bookmarks and tags show beside their heads,
83
unless they have more than three. A lane follows the change each one most
84
directly builds on, its newest dependency. Two edits that build on the same
85
change take two lanes, which join above it, so independent work shows side
86
by side. ` ~` means the change builds on something further down than the
87
graph draws, or not shown; ` -v` lists every dependency.
88
957fee30 Andy McCall 1 month ago ↶
89
Commit part of what changed with ` oxy commit PATH.. -m "..."` (only those
90
paths; the rest stays as uncommitted work) or ` oxy commit -i -m "..."` , which
91
offers each hunk in turn like ` git add -p` ; a hunk that another chosen hunk
92
needs, such as the directory a new file lives in, comes along by itself.
93
50a046e4 Andy McCall 1 month ago ↶
94
` status --json` prints the same for tools, with every conflict's kind, path and
95
contributing ChangeIds. On a terminal, ` status` lists each path with a mark: ` ✚ added` , ` ✎ modified` , ` ✖ removed` ,
ee06a6c5 Andy McCall 1 month ago ↶
96
` ➜ renamed` , ` ⚙ mode` . Renames are detected: a removed file and an added
97
file of the same kind whose contents are at least half alike are recorded
98
as a move of the same file, so identity survives a rename.
99
100
Files containing NUL bytes are stored whole ("opaque"); text files are
101
stored line by line and merge line by line. ` .oxyattributes` overrides the
102
guess (section 14).
103
104
Every change has two names: a ** ChangeId** (` 658990aa…` ) that survives
105
rewrites, and a content hash (` #7469d16c…` ) that changes when the change is
106
edited. Use whichever you have; prefixes work.
107
fbda43e7 Andy McCall 1 month ago ↶
108
## 3a. Bookmarks: branches without merges
109
110
A bookmark names a state; each workspace works on one (` main` to begin
111
with). Because changes commute, "merging" is the union of two bookmarks'
112
heads, with no merge change and any real conflict recorded as in section 6.
113
114
```
115
oxy bookmark create feature # at the working copy's base
116
oxy bookmark switch feature # check it out; commits now go here
117
oxy commit -m "Feature work"
118
oxy bookmark switch main
119
oxy merge feature # main now holds both; working copy follows if clean
120
oxy bookmark list # ● current, heads, ↑n/↓n against origin
121
oxy push -b feature # publish a bookmark other than the current one
122
oxy bookmark set feature 658990aa # move it; oxy bookmark delete feature to drop it
123
```
124
125
` oxy checkout feature` materialises a bookmark without switching to it, and
126
a bookmark name works wherever a change is expected when it has one head.
127
Each workspace remembers its own bookmark, so two directories can sit on
128
two bookmarks of one repository.
129
4fe7d604 Andy McCall 1 month ago ↶
130
** A state is its heads, not a history.** If you are coming from Git, this
131
is the one thing to know. A bookmark holds its heads and what they depend
132
on, and a change depends only on the changes it builds on (the files it
133
touched), not on everything recorded before it. So on a bookmark with
134
several heads, a new bookmark at one change can be a much older-looking
135
tree. ` oxy bookmark create NAME CHANGE` refuses when that would leave out
136
earlier work and lists what it would lack. Then pick one:
137
138
```
139
oxy bookmark create logo 745307b4 --upto # everything here up to that change, as a Git branch would be
140
oxy bookmark create logo 745307b4 --only # just that change and what it depends on
141
oxy bookmark create logo # the whole current state, usually what you want
142
```
143
06d16dc2 Andy McCall 1 month ago ↶
144
` oxy bookmark set NAME CHANGE` asks the same when the move would lose
145
changes the bookmark holds that were recorded before CHANGE, and takes
146
` --upto` and ` --only` too. After merging a proposal's target into its
147
bookmark to resolve conflicts, ` oxy bookmark set NAME CHANGE --upto`
148
keeps everything the bookmark held.
149
4fe7d604 Andy McCall 1 month ago ↶
150
` oxy bookmark switch` says when the bookmark you switch to lacks changes
151
that the one you left has.
152
14edbaaf Andy McCall 1 month ago ↶
153
** A remote's bookmarks.** A clone fetches every change, checks out the
154
remote's default bookmark, and names the others ` origin/NAME` : use them
155
anywhere a bookmark is expected (` oxy log origin/develop` ,
156
` oxy diff main origin/develop` ). ` oxy bookmark list --all` shows them.
157
` oxy bookmark switch develop` makes a local ` develop` from ` origin/develop`
158
when there is none, and ` oxy pull` then keeps every local bookmark up to
159
date with the remote's of the same name, not only the current one. Pulling
160
is a union, so this never loses work.
161
162
```
163
oxy clone https://oxygenhub.io/owner/game --recursive # subrepos too
164
oxy bookmark list --all
165
oxy bookmark switch develop # from origin/develop
166
oxy pull # updates develop, main and the rest
167
```
168
314db9b4 Andy McCall 1 month ago ↶
169
### A develop / feature flow
170
171
Names with ` /` work everywhere, pushing included:
172
173
```
174
oxy bookmark create feature/42-login # at the working copy's base
175
oxy bookmark switch feature/42-login --carry # started already? take the edits along
176
oxy commit -F msg.txt # a long message from a file
177
oxy push -b feature/42-login
178
oxy bookmark switch develop
179
oxy merge feature/42-login # the working copy follows when it was clean
180
oxy push # develop, with the feature in it
181
oxy bookmark delete feature/42-login # oxy push --delete feature/42-login on the remote
182
```
183
184
` bookmark switch` stops when the working copy has uncommitted edits, so
185
nothing is lost by accident. There are two ways past it:
186
- ` --carry` takes the edits along. It is refused only when the target
187
bookmark has other versions of the files they touch.
188
- ` --discard` drops the edits.
189
190
` oxy describe` names what the working copy holds, for build stamps:
191
- a tag, when a tag holds exactly this state;
192
- otherwise the nearest tag with the distance from it and the change;
193
- or, with no tag behind it, the bookmark and the change;
194
- with ` -dirty` added when there are uncommitted edits.
195
ee06a6c5 Andy McCall 1 month ago ↶
196
## 4. Fix up history
197
198
Oxygen keeps its own record of every operation, so all of these are safe to
199
try and to undo.
200
201
```
202
oxy describe -m "Better message" # reword the head the working copy sits on
203
oxy describe 658990aa -m "..." # reword any change; dependents are rewritten
204
oxy amend # fold the working copy into the head
205
oxy amend --into 658990aa # fold it into an older change
206
oxy split 658990aa src/parser.rs # split a head: those paths become a separate first change
207
oxy abandon 658990aa # drop a change; its content stays on disk
728da0f9 Andy McCall 1 month ago ↶
208
oxy squash 658990aa --into 9df9ac29 # fold a change into one it depends on
209
oxy rebase 658990aa --onto feature # re-express a change against another base
e266b7d4 Andy McCall 1 month ago ↶
210
oxy rebase 658990aa --onto develop --into-working-copy # conflicted? resolve it here, then commit
ee06a6c5 Andy McCall 1 month ago ↶
211
oxy undo # undo the last operation, whatever it was
98a1620a Andy McCall 1 month ago ↶
212
oxy op log # every operation, what it changed, and its command
ee06a6c5 Andy McCall 1 month ago ↶
213
```
214
98a1620a Andy McCall 1 month ago ↶
215
### The operation log
216
217
Every command that changes the repository records an operation: the
218
bookmarks, tags and working copy as they were after it. ` oxy op log` lists
219
them newest first, each with what it changed and the command that did it;
220
working-copy snapshots fold into one row.
221
222
```
223
@ 13adb0d0b8bf just now
224
│ main: 1 → 2 heads; working copy now 91ab4d50
225
│ oxy commit -m "Third"
226
○ fa21727d70da just now
227
│ created bookmark test (1 head)
228
│ oxy bookmark create test
229
○ 2d15930afdef … 830168a3ddcd just now
230
│ 2 working-copy snapshots
231
```
232
233
Any operation can be looked at, gone back to, or undone alone:
234
235
```
236
oxy --at-op fa21727d log # the log as it was after that operation; any read-only command works
237
oxy op restore fa21727d # bookmarks and working copy as they were then
238
oxy op revert fa21727d # undo just that operation, keeping everything after it
239
oxy undo # takes back the last command, a restore included
240
```
241
242
` op restore` and ` op revert` are operations themselves, so ` oxy undo` takes
243
them back. ` op revert` puts back each bookmark the operation moved, unless
244
it has moved again since. Tags and the trust policy never go backwards.
245
` undo` brings the files back as well when nothing uncommitted would be
246
lost; an undone commit's edits stay on disk as uncommitted work.
247
248
Commands that move the working copy end by saying where it is:
249
250
```
251
* Committed 95245a21 #35bbf5097e0c Third
252
Working copy 91ab4d50
253
Bookmark main: 2 heads, newest 95245a21 Third
254
```
255
ee06a6c5 Andy McCall 1 month ago ↶
256
Rewriting a change that others depend on rewrites them too, keeping their
728da0f9 Andy McCall 1 month ago ↶
257
ChangeIds. Because unrelated changes already coexist, ` rebase` is rarely
258
needed; its job is to change what a change is said to build on, for instance
259
to drop a dependency on something you are about to abandon. Where a dependent referred to a line that no longer exists, the
ee06a6c5 Andy McCall 1 month ago ↶
260
reference is re-anchored to the nearest surviving line and ` oxy abandon`
261
prints a note about it.
262
957fee30 Andy McCall 1 month ago ↶
263
## 4a. Who wrote this, and what broke it
264
265
```
266
oxy blame src/parser.rs # every line: the change that introduced it, author, age
267
oxy blame src/parser.rs --json
268
```
269
270
Blame is exact: each line is an atom that remembers the change that
271
introduced it, so renames cost nothing and there is no heuristic.
272
273
```
274
oxy bisect start
275
oxy bisect good v1.2 # a change, bookmark or tag known to be fine
276
oxy bisect bad main # and one known to be broken
277
oxy bisect run make test # exit 0 good, 125 skip, anything else bad
278
oxy bisect reset # back to where you were
279
```
280
281
Without ` run` , each step checks out a state to test and you answer with
282
` oxy bisect good` , ` bad` , or ` skip` . The candidates are the changes the bad
283
state has that the good one lacks, ordered so every tested state is
284
well-formed; the answer is the first change whose inclusion breaks things.
285
ee06a6c5 Andy McCall 1 month ago ↶
286
## 5. Move around
287
288
```
289
oxy checkout # the bookmark's heads
290
oxy checkout 658990aa # the state of one change and its dependencies
291
oxy checkout v1.2 # a tag
292
oxy checkout --discard ... # throw away uncommitted work first
293
```
294
295
Checking out a single older change gives you the files that change and its
296
dependencies touch, not a full snapshot from that date: in Oxygen a change
297
depends only on what it actually builds on.
298
299
## 6. Conflicts
300
301
A conflict never stops a commit, fetch, or pull. It is recorded in the
302
state and shown by ` oxy status` , which exits with status 2 while any
303
conflict remains. Conflicted text files are written with markers:
304
305
```
306
<<<<<<< oxy conflict 1 of 2, side 1: change k7m2p9 "Add retry loop"
307
... lines ...
308
======= oxy conflict 1 of 2, side 2: change q3x8w1 "Refactor client"
309
... lines ...
310
>>>>>>> oxy conflict 1 of 2 end
311
```
312
313
Edit the file to what it should be (keep one side, both, or neither) and
314
remove the markers. Tree conflicts, such as two files wanting the same
315
name, appear as ` <name>.oxy-conflict-<n>` candidates: keep the one you
316
want under the right name and delete the rest.
317
318
```
319
oxy resolve # which conflicts your edits resolve, which still have markers
320
oxy commit -m "Resolve retry vs refactor"
321
```
322
323
The commit is recorded as a * resolution* , a change that depends on every
324
side of the conflict; anyone who fetches it gets the conflict resolved.
325
326
## 7. Work with others
327
328
Run a server (any machine with the repositories under one directory):
329
330
```
331
oxy serve --root /srv/oxy --bind 0.0.0.0:8890 --token SECRET \
332
--tls-cert cert.pem --tls-key key.pem
333
```
334
335
Without ` --tls-*` the server speaks plain HTTP; keep that on a loopback
336
address or behind a TLS terminator. ` --token` makes pushes require a bearer
337
token; reads stay open.
338
339
On your machine:
340
341
```
ff1f62fe Andy McCall 1 month ago ↶
342
echo SECRET | oxy auth login https://host:8890 --with-token --ca my-ca.pem
ee06a6c5 Andy McCall 1 month ago ↶
343
oxy clone https://host:8890/project
344
cd project
345
oxy push
346
oxy pull
347
```
348
ff1f62fe Andy McCall 1 month ago ↶
349
` --ca` is only for a server with a self-signed certificate. On a hub such as
350
OxygenHub, ` oxy auth login https://oxygenhub.io` signs in through the
351
browser instead: it shows a code to approve on the hub, and the hub issues a
352
token that lasts 90 days past its last use.
353
354
### Signing in
355
356
` oxy auth login HUB` keeps one token per hub (scheme, host and port) in
357
` ~/.config/oxy/credentials.toml` , readable by you only, and every repository
358
on that hub uses it: clone, fetch, push and subrepos alike. Nothing secret is
359
written into a checkout. ` oxy auth status` lists the hubs you are signed in
360
to and checks each token with its hub; ` oxy auth logout HUB` forgets the token
361
and revokes it on the hub.
362
363
To keep tokens in the system keyring instead, name a Git credential helper:
364
` oxy config --user auth.helper libsecret` (Linux), ` osxkeychain` (macOS) or
365
` manager` (Windows). The file then keeps only the account and CA.
366
367
A token is found in this order: the remote's own ` remote.<name>.token` , then
368
` $OXY_TOKEN` (for CI), then the store, then a remote on the same hub in an
369
enclosing checkout (so a subrepo uses its parent's). oxy sends a token over
370
` https` only, or over plain ` http` to this machine; it is never sent to
371
another host after a redirect, and a credentials file that others can read
372
is ignored.
373
ee06a6c5 Andy McCall 1 month ago ↶
374
- ` oxy fetch` updates ` origin/main` without touching your bookmark.
14edbaaf Andy McCall 1 month ago ↶
375
- ` oxy pull` fetches, then makes your bookmark, and every other local
376
bookmark the remote also has, the union of both sides.
ee06a6c5 Andy McCall 1 month ago ↶
377
There is no merge commit; unrelated changes simply coexist, and a real
378
conflict is recorded as in section 6. The working copy follows when it was
379
clean.
380
- ` oxy push` sends your changes and moves the remote bookmark. If the remote
381
moved since you last fetched, the push is refused: pull and push again.
382
` --force` overrides the compare-and-swap.
383
- ` oxy remote add|remove|list` manages remotes; the clone source is ` origin` .
384
385
A repository can also be cloned from a local path, which is handy for tests
386
and for a bare "hub" on a shared disk.
387
388
## 8. Decide who may publish: the trust policy
389
390
Without a policy a repository is * unverified* : everything is accepted and
391
every remote command says so. A policy names root keys and the keys allowed
392
to update each bookmark; servers and clients enforce it.
393
394
```
395
oxy policy init # your key becomes the only root; push publishes it
396
oxy policy show
397
oxy policy grant alice.identity # alice.identity came from her `oxy identity export`
398
oxy policy grant ci.identity --pattern 'release/*'
399
oxy policy revoke 9458b656 # by KeyId prefix
400
oxy verify # signature status of every change in the log
401
```
402
403
Several people can hold root keys:
404
405
```
406
oxy policy root add bob.identity
407
oxy policy root threshold 2 # future updates need two root signatures
408
```
409
410
Once the threshold is above one, an update you make alone becomes a
411
* proposal file* (` policy-<serial>.proposal` , or ` --out` ). Send it to another
412
root holder, who runs ` oxy policy sign policy-7.proposal` ; whoever completes
413
the threshold applies it, and the next push publishes it. Everyone else
414
picks it up on fetch, verifying each step from the policy they already
415
trust.
416
417
## 9. Keys over time
418
419
```
420
oxy identity rotate # fresh key pair; old signatures stay valid
421
oxy identity renew --expires 365 # same keys, new expiry in days (0 = never)
7ba155f2 Andy McCall 1 month ago ↶
422
oxy identity delegate add agent.identity --expires 8h # sign changes for me today
423
oxy identity delegate add ci.identity --scope changes,refs # sign and push for me
ee06a6c5 Andy McCall 1 month ago ↶
424
oxy identity delegate remove 3f2a…
7ba155f2 Andy McCall 1 month ago ↶
425
oxy identity revoke 3f2a… --reason "agent host compromised" # a key you delegated to
445ce913 Andy McCall 1 month ago ↶
426
```
427
428
Setting an agent up takes a home of its own, so it never holds your
429
secret key. In the agent's shell, inside any checkout:
430
431
```
432
export OXY_HOME=~/.oxy-agents/claude
433
oxy identity create --name "Claude Code on my laptop" --email [email protected]
434
# prints the agent's KeyId; its identity file is keys/<KeyId>.identity in that home
435
oxy config --user author.name "Your Name" # the agent authors as you…
436
oxy config --user author.email "[email protected] "
437
oxy config --user author.key <YOUR KeyId>
438
oxy config --user author.signer <THE AGENT's KeyId> # …and signs as itself
439
oxy config --user core.sign change
440
```
441
442
Then, in your own shell, in the repository: ` oxy identity delegate add
443
~/.oxy-agents/claude/keys/<KeyId>.identity --scope changes --expires 8h`
614f55e1 Andy McCall 1 month ago ↶
444
(several files at once are one rotation). This rotates your identity:
445
the new key is written to your user config, and to this repository's
446
file too if it pinned the old one, so other checkouts follow; put the
447
new KeyId in each agent's ` author.key` , and re-link it on your hub.
448
` oxy identity show` warns if a repository still pins an older key
449
(` oxy config --unset author.key` there). Every commit the agent makes
445ce913 Andy McCall 1 month ago ↶
450
carries you as author and its signature: ` oxy log -r 'delegated()'`
451
lists them, ` oxy verify` names the agent, and its own ` oxy push` is
452
refused under any policy, so you land its work.
453
454
```
ee06a6c5 Andy McCall 1 month ago ↶
455
oxy identity revoke # retire your own key
456
oxy identity revoke 3f2a… --reason "laptop stolen" # any key, if you hold a root
457
```
458
459
Rotation, renewal, and delegation all issue a successor identity that names
460
the previous one. If a policy names your key, it is updated to the successor
461
in the same step (as a proposal when more root signatures are needed).
462
Changes signed before the rotation remain authorised; a revoked key
463
authorises nothing. ` oxy verify` shows signatures by revoked keys as valid
464
but revoked.
465
466
## 10. Tags and workspaces
467
468
```
469
oxy tag create v1.2 -m "First release" # the current heads; or name changes
470
oxy tag list
471
oxy workspace add ../project-hotfix # a second checkout sharing the repository
472
oxy workspace list
473
oxy workspace forget ../project-hotfix
474
```
475
476
A tag is an immutable state, signed when you have a key, and travels with
477
push and fetch. Workspaces have their own working copy and bookmark
478
(` workspace.bookmark` ) but share objects and history.
479
fc1a466a Andy McCall 1 month ago ↶
480
### Receipts from CI
481
482
A runner such as OxygenFlow signs a receipt for every job it runs: what ran,
483
in what environment, on which files, and the result. Receipts are kept with
484
the state they ran on.
485
486
```
487
oxy receipt list # receipts for the bookmark's state
488
oxy receipt show 3f2a9c # one in full, with its signature checked
489
oxy receipt export 3f2a9c build.receipt # hand it to someone
490
oxy receipt verify build.receipt # check one without keeping it
491
oxy receipt import build.receipt # verify and keep it
492
```
493
ee06a6c5 Andy McCall 1 month ago ↶
494
## 11. Big repositories: partial, sparse, shallow
495
496
```
497
oxy clone URL --max-blob 1M # files above 1 MiB are fetched on first read
498
oxy clone URL --sparse src --sparse docs # materialise only these subtrees
499
oxy clone URL --depth 50 # only the last 50 levels of history
500
oxy sparse src docs tests # change the filter later
501
oxy deepen 100 # fetch more history below the boundary
502
```
503
504
Lazy blobs and sparse trees do not affect commits: what you do not have is
505
left exactly as it was. A shallow clone starts from a * checkpoint* of the
506
state, so status and commit work at full speed from the first minute.
507
4dee277c Andy McCall 1 month ago ↶
508
## 11a. Nested repositories (submodules)
509
510
A subrepo is another repository checked out at a path and pinned to a state,
511
Oxygen or Git. The pin is versioned like a file, so two people pinning
512
different states get an ordinary conflict.
513
514
```
515
oxy submodule add https://host/lib.git libs/lib # Git or Oxygen URL; records .oxymodules
516
oxy commit -m "Add lib" # the pin is committed with the parent
517
oxy submodule status # pin vs what is on disk
518
oxy submodule update --init # after a clone: fetch nested repositories
519
oxy submodule remove libs/lib # drop the node; the directory stays
520
```
521
522
Committing the parent records whatever the nested repository is at, and
523
checking out an older parent state moves the nested repository back, unless
524
it has uncommitted changes, which are never overwritten. An absent nested
7993d465 Andy McCall 1 month ago ↶
525
repository keeps its pin until you run ` update --init` . A ` .oxymodules`
526
section written by hand has no pin until ` oxy submodule add` clones it;
527
` status` and ` update` name such entries, and ` update` exits non-zero. Git
528
submodules survive ` oxy git import` as Git pins and go back out as gitlinks
529
on export.
4dee277c Andy McCall 1 month ago ↶
530
ee06a6c5 Andy McCall 1 month ago ↶
531
## 12. Git interoperability
532
533
```
534
oxy git import ../project.git ./project-oxy --branch main # convert a Git history
535
oxy git fetch https://github.com/you/project.git # bring new Git commits in
536
oxy git push https://github.com/you/project.git # publish your changes to Git
537
oxy git export ../mirror.git # a plain Git mirror of the bookmark
538
```
539
540
Import turns each commit into one change (merge commits become
541
resolutions), keeps authors and hashes as ` Git-Author` /` Git-Commit`
542
trailers, detects renames, and skips submodules. ` git fetch` /` git push` keep
543
a bare mirror under ` .oxy/git/` ; a push is refused until the remote's tip
544
has been fetched, so it always fast-forwards. Exported commits carry
545
` Change-Id` and ` Oxy-Hash` trailers.
546
547
## 13. Automate: hooks
548
549
Executables in ` .oxy/hooks/<event>` (never cloned) receive one JSON object
550
on stdin. ` pre-commit` , ` pre-push` and other ` pre-*` hooks veto by exiting
551
non-zero, and their stderr becomes the error message. Events:
552
` pre-commit` , ` post-commit` , ` pre-push` , ` post-fetch` , ` post-checkout` , and
553
` semantic-deps` , which runs at commit when ` hooks.semantic-deps = true` and
554
answers ` {"deps": ["<hash>", …]}` to make the change depend on more than it
555
textually references.
556
557
## 14. Per-path attributes, ignores, locks
558
559
` .oxyattributes` uses gitattributes syntax:
560
561
```
562
*.png binary
563
*.txt text eol=lf
564
*.psd lockable nocompress
565
```
566
567
` binary` /` text` override content sniffing, ` eol=lf|crlf` normalises line
568
endings in the store and on checkout, ` nocompress` stores chunks raw, and
569
` lockable` files are checked out read-only until you take the local lock:
570
571
```
572
oxy lock assets/logo.psd
573
oxy unlock assets/logo.psd
574
```
575
576
Locks are advisory and local; server-side locks are planned.
577
578
## 15. Configuration
579
580
Two files, both ` key = "value"` lines: ` ~/.config/oxy/config.toml`
581
(` oxy config --user KEY VALUE` ) and ` .oxy/config` (` oxy config KEY VALUE` ).
d443639b Andy McCall 1 month ago ↶
582
The repository file wins. ` OXY_HOME` relocates the user directory. ` OXY_TIMINGS=1` prints how long each phase of a snapshot takes (loading the base state, rendering it, reading the working copy, building the change) to standard error, for finding out where a slow command spends its time. Built with ` cargo build --release --features alloc-stats` , oxy also reports each phase's live and peak memory and what it allocated, and a summary at the end.
ee06a6c5 Andy McCall 1 month ago ↶
583
584
585
586
| ` author.name` , ` author.email` , ` author.key` | who you are; ` key` is set by ` identity create` |
ff1a64f8 Andy McCall 1 month ago ↶
587
| ` author.signer` | the key that signs instead of ` author.key` : an agent's own key, which your identity lists as a delegate (also ` $OXY_SIGNER` ) |
ee06a6c5 Andy McCall 1 month ago ↶
588
| ` core.sign` | ` change` to sign every commit; otherwise seals at push |
589
| ` core.op-retention` | days for which old operations keep their states alive (90) |
590
| ` core.gc-grace` | days an unreachable object survives (14) |
591
| ` core.checkpoint-interval` | changes between automatic checkpoints (256) |
592
| ` filter.max-blob` , ` filter.paths` | lazy blobs and sparse subtrees (section 11) |
593
| ` hooks.semantic-deps` | run the semantic-deps hook at commit |
594
| ` workspace.bookmark` | this workspace's bookmark (` main` ) |
ff1f62fe Andy McCall 1 month ago ↶
595
| ` remote.<name>.url` , ` .token` , ` .ca` | remotes; token and CA fall back to ` OXY_TOKEN` and ` OXY_CA` , then ` oxy auth login` 's store |
596
| ` auth.helper` (user file) | a Git credential helper to keep ` oxy auth` tokens in, such as ` libsecret` |
ee06a6c5 Andy McCall 1 month ago ↶
597
598
## 16. Shell prompt
599
600
` oxy prompt` prints ` main 658990aa*+2` (bookmark, working copy, ` *` dirty,
601
` !` conflicted, ahead/behind origin) in a few milliseconds and records
602
nothing. See [ prompt.md ] ( prompt.md ) for bash, oh-my-bash, zsh, and fish
603
snippets and the ` --format` placeholders.
604
605
## 17. Housekeeping
606
607
```
da652d63 Andy McCall 1 month ago ↶
608
oxy gc # prune unreachable objects past the grace period, repack into one pack
ee06a6c5 Andy McCall 1 month ago ↶
609
oxy gc --now # ignore the grace period (only when nothing else is writing)
387335ff Andy McCall 1 month ago ↶
610
oxy fsck # check every object, the op log, references, signatures, checkpoints
3e5772cc Andy McCall 1 month ago ↶
611
oxy doctor # check identity, config and remotes, with what to do about each problem
ee06a6c5 Andy McCall 1 month ago ↶
612
oxy checkpoint # serialise the bookmark's state so large histories load instantly
613
```
614
615
Both run automatically: packing when loose objects pile up, checkpoints
616
every ` core.checkpoint-interval` changes.
617
c6aa5bd9 Andy McCall 1 month ago ↶
618
## 17a. Scripting and editors
619
620
Every reporting command takes ` --json` (` status` , ` log --path` , ` show` ,
621
` diff` , ` hunks` , ` blame` , ` resolve` , ` op log` , ` bookmark list` , ` remote list` ,
622
` fetch` , ` pull` , ` push` , ` submodule status` , ` bisect status` , ` verify` ,
623
` policy show` , ` root` , ` version` ). ` oxy cat PATH -r CHANGE` prints a file as
624
it was, ` oxy discard PATH..` restores files to the base, and ` oxy hunks`
625
numbers the working copy's hunks for ` commit --hunks` and ` discard --hunks` .
626
ee06a6c5 Andy McCall 1 month ago ↶
627
## 18. If something looks wrong
628
629
- ** "the remote has change … which you do not; pull first"** : someone
630
pushed since your last fetch. ` oxy pull` , then push.
631
- ** "policy needs N root signature(s)"** on fetch: the server's policy was
632
updated in a way your copy cannot verify. Ask a root holder whether the
633
chain of updates was published; a fresh clone trusts the current policy.
634
- ** ` oxy status` exits 2** : conflicts remain; see section 6.
635
- ** Many heads on ` main` ** : independent changes that do not reference one
636
another. Nothing to fix; the state is their union.
637
- ** Undo anything** : ` oxy undo` reverts the last operation, including
638
pulls, checkouts, and rewrites.
d42369ab Andy McCall 1 month ago
639
640
## Shell completions and man pages
641
642
``` sh
643
oxy completions bash > ~/.local/share/bash-completion/completions/oxy # bash
644
oxy completions zsh > "${fpath[1]}/_oxy" # zsh
645
oxy completions fish > ~/.config/fish/completions/oxy.fish # fish
646
oxy man --dir ~/.local/share/man/man1 # then: man oxy-commit
647
```
648
649
The oh-my-bash plugin in ` contrib/oh-my-bash` loads the bash completions itself.