| 1 |
{% extends "base.html" %} |
| 2 |
{% block title %}Help{% endblock %} |
| 3 |
{% block content %} |
| 4 |
<div class="head"><h1>Help <small>using {{ shell.site }}</small></h1></div> |
| 5 |
<div class="sectioned help"> |
| 6 |
<nav class="section-nav" aria-label="Sections"> |
| 7 |
<a href="#start">Getting started</a> |
| 8 |
<a href="#identity">Your identity</a> |
| 9 |
<a href="#push">Pushing</a> |
| 10 |
<a href="#clone">Cloning</a> |
| 11 |
<a href="#proposals">Proposals</a> |
| 12 |
<a href="#delegate">Letting the hub act for you</a> |
| 13 |
<a href="#flow">Pipelines</a> |
| 14 |
<a href="#keys">Keyboard</a> |
| 15 |
<a href="#glossary">Coming from GitHub</a> |
| 16 |
</nav> |
| 17 |
<div class="sections"> |
| 18 |
|
| 19 |
<section class="panel" id="start"> |
| 20 |
<h2>Getting started</h2> |
| 21 |
<p>{{ shell.site }} hosts <strong>Oxygen</strong> repositories. You work with them through <code>oxy</code>, the Oxygen client; the hub shows them, reviews them and runs their pipelines. Every command below is filled in for this hub.</p> |
| 22 |
<ol> |
| 23 |
<li>Install <code>oxy</code>: build it from the <code>oxygen</code> repository with <code>cargo build --release</code> and put <code>target/release/oxy</code> on your path.</li> |
| 24 |
<li>Say who you are and make a signing identity (next section).</li> |
| 25 |
<li>{% if shell.user.is_some() %}Create a <a href="/settings/tokens">personal access token</a>{% else %}<a href="/register">Register</a>, then create a personal access token under Settings › Tokens{% endif %} with <code>repo:write</code>. It is shown once; keep it in <code>oxy</code>'s configuration, not in scripts.</li> |
| 26 |
<li>{% if shell.user.is_some() %}<a href="/new">Create a repository</a>{% else %}Create a repository with <strong>+ NEW</strong>{% endif %} and push to it (below). An empty repository shows the same commands, with its own address.</li> |
| 27 |
</ol> |
| 28 |
<p class="small mute"><code>oxy doctor</code> checks your identity, configuration and remotes, and says what to do about any problem.</p> |
| 29 |
</section> |
| 30 |
|
| 31 |
<section class="panel" id="identity"> |
| 32 |
<h2>Your identity</h2> |
| 33 |
<p>Oxygen changes are signed. Your identity is a key pair (Ed25519 with ML-DSA-65) kept under <code>~/.config/oxy</code>; the public part travels with your changes.</p> |
| 34 |
{% let cmd = "oxy config --user author.name \"Your Name\"\noxy config --user author.email [email protected]\noxy identity create\noxy config --user core.sign change" %} |
| 35 |
<div class="cmds"><pre><code>{{ cmd }}</code></pre><button class="small" data-copy="{{ cmd }}">copy</button></div> |
| 36 |
<p>Link the key to your account under {% if shell.user.is_some() %}<a href="/settings/keys">Settings › Keys</a>{% else %}Settings › Keys{% endif %}: the page gives you a challenge to sign with <code>oxy identity sign-challenge</code>, which proves you hold the key. Linked keys show on your profile, and the hub can then tell which signed changes are yours.</p> |
| 37 |
</section> |
| 38 |
|
| 39 |
<section class="panel" id="push"> |
| 40 |
<h2>Pushing</h2> |
| 41 |
<p>From a checkout, add the repository as a remote, give it your token, and push{% if q.ca_url.is_some() %}. This hub's certificate is self-signed, so the commands also save it and point the remote at it{% endif %}:</p> |
| 42 |
{% let cmd = q.connect(self.repo_url().as_str()) %} |
| 43 |
<div class="cmds"><pre><code>{{ cmd }}</code></pre><button class="small" data-copy="{{ cmd }}">copy</button></div> |
| 44 |
<p>An empty repository takes its identity from the first push, so every later clone shares it. <code>oxy push {{ q.remote }}</code> sends the current bookmark; <code>oxy push {{ q.remote }} --bookmark NAME</code> another one. Tags travel with pushes.</p> |
| 45 |
<p class="small mute">A Git history comes across with <code>oxy git import --branch main path/to/git-checkout NAME</code>: every commit becomes a change, and the result can be pushed like any other repository.</p> |
| 46 |
</section> |
| 47 |
|
| 48 |
<section class="panel" id="clone"> |
| 49 |
<h2>Cloning</h2> |
| 50 |
{% let cmd = self.clone_cmd() %} |
| 51 |
<div class="cmds"><pre><code>{{ cmd }}</code></pre><button class="small" data-copy="{{ cmd }}">copy</button></div> |
| 52 |
<p>Public repositories clone without a token. For private ones, and to push back, set <code>oxy config remote.origin.token YOUR-TOKEN</code>{% if q.ca_url.is_some() %} and <code>oxy config remote.origin.ca {{ q.ca_file }}</code>{% endif %} in the clone. <code>oxy pull origin</code> brings in what others pushed; there is no merge commit, because Oxygen changes combine by themselves.</p> |
| 53 |
</section> |
| 54 |
|
| 55 |
<section class="panel" id="proposals"> |
| 56 |
<h2>Proposals</h2> |
| 57 |
<p>A proposal asks for a bookmark's changes to be added to another bookmark, like a pull request. Push your bookmark, then open one from the repository's Proposals tab, from the compare page's <strong>Propose this</strong>, or from a fork.</p> |
| 58 |
<ul> |
| 59 |
<li>A proposal is always tested and reviewed on its <strong>projected state</strong>: exactly what the target will hold once it lands. It never goes stale, and there is nothing to rebase.</li> |
| 60 |
<li>Review comments are anchored to lines' atoms, so they stay on the right line through later pushes.</li> |
| 61 |
<li>An approval can be a <strong>seal</strong>: your signature over the proposal's changes (<code>oxy seal</code>), which anyone can check offline.</li> |
| 62 |
<li>Land from the page, or from a client with <code>oxy proposal land URL</code>, which signs the landing with your own key.</li> |
| 63 |
</ul> |
| 64 |
</section> |
| 65 |
|
| 66 |
<section class="panel" id="delegate"> |
| 67 |
<h2>Letting the hub act for you</h2> |
| 68 |
<p>Edits in the browser and landings from the proposal page are changes too, and they must be signed. The hub signs them as your <strong>delegate</strong>, only if you allow it. Allowing it is a one-off step:</p> |
| 69 |
{% let cmd = self.delegate_cmd() %} |
| 70 |
<div class="cmds"><pre><code>{{ cmd }}</code></pre><button class="small" data-copy="{{ cmd }}">copy</button></div> |
| 71 |
<p>Then link your identity again under Settings › Keys, so the hub sees the delegation. You can withdraw it at any time with <code>oxy identity delegate remove</code>; a repository's trust policy still decides whether a delegated change may update a bookmark.</p> |
| 72 |
</section> |
| 73 |
|
| 74 |
<section class="panel" id="flow"> |
| 75 |
<h2>Pipelines</h2> |
| 76 |
<p>Pipelines run in <strong>OxygenFlow</strong>. Put a pipeline in <code>.flow/pipeline.kdl</code> and push: each job runs in its own microVM with no network, and its result shows on the repository's Flow tab and as a check named <code>flow/JOB</code> on proposals. A site administrator enables Flow for a repository.</p> |
| 77 |
<p>Instead of a badge, a README can carry a <strong>state stamp</strong>:</p> |
| 78 |
{% let cmd = "[](.flow/run)" %} |
| 79 |
<div class="cmds"><pre><code>{{ cmd }}</code></pre><button class="small" data-copy="{{ cmd }}">copy</button></div> |
| 80 |
<p>It shows the result for the state you are looking at (a tag shows the tag's result), names that state, and carries each job's receipt hash.</p> |
| 81 |
</section> |
| 82 |
|
| 83 |
<section class="panel" id="keys"> |
| 84 |
<h2>Keyboard</h2> |
| 85 |
<table class="list"> |
| 86 |
<tbody> |
| 87 |
<tr><td><kbd>/</kbd></td><td>Search</td></tr> |
| 88 |
<tr><td><kbd>g</kbd> <kbd>c</kbd></td><td>The repository's code</td></tr> |
| 89 |
<tr><td><kbd>g</kbd> <kbd>h</kbd></td><td>History of the bookmark you are on</td></tr> |
| 90 |
<tr><td><kbd>g</kbd> <kbd>p</kbd></td><td>Proposals</td></tr> |
| 91 |
<tr><td><kbd>g</kbd> <kbd>i</kbd></td><td>Issues</td></tr> |
| 92 |
<tr><td><kbd>g</kbd> <kbd>b</kbd></td><td>Bookmarks</td></tr> |
| 93 |
<tr><td><kbd>g</kbd> <kbd>t</kbd></td><td>Trust</td></tr> |
| 94 |
<tr><td><kbd>y</kbd></td><td>Replace the address with a permalink to this exact state (files and trees)</td></tr> |
| 95 |
<tr><td>click a line number, <kbd>Shift</kbd>-click another</td><td>Select lines; copy them or a permalink to them</td></tr> |
| 96 |
<tr><td><kbd>?</kbd></td><td>The keyboard sheet</td></tr> |
| 97 |
</tbody> |
| 98 |
</table> |
| 99 |
</section> |
| 100 |
|
| 101 |
<section class="panel" id="glossary"> |
| 102 |
<h2>Coming from GitHub</h2> |
| 103 |
<table class="list glossary"> |
| 104 |
<thead><tr><th>GitHub</th><th>Here</th><th>What is different</th></tr></thead> |
| 105 |
<tbody> |
| 106 |
<tr><td>commit</td><td><strong>change</strong></td><td>A change records edits, not a snapshot, and names the changes it depends on. Changes that do not touch the same lines combine in any order with the same result, so there are no merge commits. A change keeps its identity when it is rebased or squashed.</td></tr> |
| 107 |
<tr><td>commit SHA, tree</td><td><strong>state</strong></td><td>The files a set of changes makes. A state is addressed by its heads (<code>a1b2…+c3d4…</code>); checks, stamps and permalinks belong to states.</td></tr> |
| 108 |
<tr><td>branch</td><td><strong>bookmark</strong></td><td>A name for a state. It can have several <strong>heads</strong> (changes nothing else depends on); the tree is their union, not a conflict.</td></tr> |
| 109 |
<tr><td>tag</td><td><strong>tag</strong></td><td>An immutable named state, usually signed.</td></tr> |
| 110 |
<tr><td>merge, rebase</td><td><code>oxy merge</code>, <code>oxy pull</code></td><td>Uniting bookmarks adds the other side's changes. Nothing is rewritten and no merge change is made.</td></tr> |
| 111 |
<tr><td>merge conflict</td><td><strong>conflict</strong> in the state</td><td>A conflict is recorded in the history instead of blocking you. It stays visible (the Conflicts tab) until a change resolves it, and anyone can resolve it later.</td></tr> |
| 112 |
<tr><td>pull request</td><td><strong>proposal</strong></td><td>Reviewed and tested on its projected state. It cannot go stale, and approvals can be signed seals.</td></tr> |
| 113 |
<tr><td>branch protection</td><td><strong>trust policy</strong></td><td>Signed rules in the repository itself: who may move which bookmark, with how many signatures. Every client enforces them, not only the hub.</td></tr> |
| 114 |
<tr><td>Actions, CI badge</td><td><strong>OxygenFlow</strong>, state stamp</td><td>Jobs run in microVMs on exact states; results are receipts, and the stamp says which state they belong to.</td></tr> |
| 115 |
<tr><td>git blame</td><td><strong>blame</strong></td><td>Exact through rebases and squashes: each line is an atom with one authoring change, so there is no "ignore revisions" file.</td></tr> |
| 116 |
<tr><td>fork</td><td><strong>fork</strong></td><td>A copy under your name with its own identity and bookmarks, sharing the stored objects. Its proposals go upstream as <code>you/name:bookmark</code>; the upstream's trust policy is not copied.</td></tr> |
| 117 |
<tr><td>personal access token</td><td><strong>token</strong></td><td>For pushing and the API. Your signing key is what proves authorship; a token only authorises.</td></tr> |
| 118 |
</tbody> |
| 119 |
</table> |
| 120 |
</section> |
| 121 |
|
| 122 |
</div> |
| 123 |
</div> |
| 124 |
{% endblock %} |