OXYGENHUB
# 827281eed2ed oxygen / CHANGELOG.md
7.8 KiB · Markdown · last changed Fetch reports how each bookmark stands against the remote's copy 1 month ago renderedsource blame history raw

Changelog

Unreleased

  • Fetch says when a bookmark is behind (#56). oxy fetch reports each bookmark against the remote's copy ("main is 1 change behind: oxy pull to take it", ahead, diverged) and says "up to date" only when they match; --json gives ahead and behind. A change that was fetched but not pulled resolves by id or hash, and oxy show says it is only in origin/main. With one remote not called origin, fetch, pull and push use it, and bookmark list and the prompt count against it.

  • Blame twice as fast (#41). oxy blame prints through a buffered writer and formats each change once, and the state index's tree view loads in one step: blame of the Linux tree's MAINTAINERS (30 000 lines) is 0.08 s, from 0.16 s; tuned Git 0.06 s. The faster tree view also takes 16 ms off diff, commit and checkout.

  • oxy log in milliseconds (#41). Log no longer checks the files on disk: its working-copy row shows the working copy as last recorded, "(working copy)" or "(working copy, uncommitted changes)", as Git's log never looks at the working tree; oxy status checks the disk. log -n 100 is 0.03 s on the Linux tree (from 0.17 s) and 0.02 s on a 10 000-commit history.

  • Status twice as fast as Git on the Linux tree (#41). With uncommitted work, oxy status answers from a status cache while every file is as the last snapshot left it, and the manifest keeps every directory's time, so the tree is listed only when a directory's entries changed. One edited file is 0.10 to 0.12 s (from 0.44 s; Git 0.22 s) and a clean status 0.09 to 0.12 s (Git 0.20 to 0.26 s), in 80 MB. oxy diff renders the working copy from the cache too (0.20 s, from 0.41 s; Git 0.08 s). A commit after a status takes that status's snapshot instead of walking the tree again (0.37 s, from 0.68 s; Git 0.15 s). A file written within the racy window is now hashed by the prompt's check too, as it was by status.

  • Quieter notes (#55). Notes start with a dimmed › instead of ℹ, which many terminal fonts draw as a boxed or emoji-style "i". A spinner's final line no longer shows two ticks or runs into the next line.

0.2.0 (2026-10-01)

  • The operation log says what each operation did (#51). oxy op log gives each operation a summary, such as "main: 1 → 2 heads; working copy now 91ab4d50", with its command dimmed beneath. Runs of working-copy snapshots fold into one row, and -n limits the listing. --json adds each operation's changes.

  • oxy op restore, oxy op revert and --at-op (#52). op restore OP brings back the bookmarks and working copy as they were after OP. op revert OP undoes OP alone and keeps everything after it. --at-op OP runs any read-only command on the repository as it was then. Restore and revert are operations too, so oxy undo takes them back. undo now takes back a command's own checkout with it (pull and restore record one), and brings the files back when nothing uncommitted would be lost.

  • Commands say where they left you (#53). Commit, checkout, switch, rebase, merge, amend, abandon, pull, undo, restore and revert end with the working copy and the bookmark's heads, newest first, as jj does.

  • oxy log is a graph (#50). Each change takes two lines: its ID (the shortest unique prefix bright), author, time, bookmarks and tags, hash and signature, then its subject. Lanes follow the change each one most directly builds on, and join where two lines of work meet, so independent work shows side by side. A dependency further than twelve rows down is marked ~, which keeps the graph to a few lanes even on a long history. --json is unchanged.

  • A remote's bookmarks work like local ones (#48).

    • origin/NAME names a remote's bookmark wherever a bookmark is expected, and oxy bookmark list --all lists those with no local bookmark.
    • oxy bookmark switch NAME makes a local bookmark from origin/NAME when there is none (REMOTE/NAME picks another remote).
    • oxy pull updates every local bookmark the remote has too, not only the current one, and names the others it moved.
    • oxy clone checks out the remote's default bookmark (servers now name it in refs), says how many other bookmarks the remote has, and takes --recursive to clone the subrepos. A clone, switch or pull says when subrepos are not at their pins.
  • A newer repository format names the oxy that cannot read it (#49). Instead of "unsupported format version 2", oxy says the data was written by a newer oxy, and gives its own version and path, which shows an older copy earlier on PATH.

  • Sign in once per hub: oxy auth login, status and logout (#47). oxy auth login https://oxygenhub.io signs in through the browser, and every repository on that hub then clones, fetches and pushes with the token, subrepos included. Nothing secret goes into a checkout any more.

    • The token is kept in ~/.config/oxy/credentials.toml, readable by you only, or in the system keyring through a Git credential helper (oxy config --user auth.helper libsecret).
    • --with-token reads a token from standard input, for CI and scripts. oxy auth logout also revokes the token on the hub.
    • A token goes over https only (plain http only to this machine), never to another host after a redirect. A credentials file that others can read is ignored.
    • Lookup order: remote.<name>.token, OXY_TOKEN, the store, then an enclosing checkout's remote on the same hub. Clones no longer copy a token into a subrepo's configuration.
    • Identity secret keys are now created owner-only, rather than tightened just after being written.

Measured on the Linux kernel's tree (95 943 files); docs/benchmarks.md has the tables.

  • Faster than Git on the first commit, a clean status, fsck, gc and the pack's size.
    • First commit: 21.9 s (Git 33.7 s).
    • Clean status: 0.17 to 0.19 s (Git 0.22 s).
    • fsck: 8.2 s (Git 12.6 s).
    • gc: 33.7 s (Git 70 s).
    • The pack: 293.5 MB (Git's 295.5 MB).
  • Level with Git on a local clone (about 17 s). Status with one file changed, diff, commit, log, blame and checkout are two to six times faster than at 0.1.0. They are still behind Git:
    • Status with one file changed: 0.41 s, against 0.22 s.
    • Commit: 0.67 s, against 0.21 s.
    • Blame: 0.16 s, against 0.07 s.
    • Checkout: 0.74 s, against 0.35 s.
  • A project's .gitignore files count, below .oxyignore. A project coming from Git no longer commits its build output, and ! in .oxyignore can bring back what .gitignore leaves out. Ignore rules still apply to untracked paths only.
  • A folder holding a repository of its own is named. oxy status, oxy commit and status --json (untracked_nested) name a folder with its own .git or .oxy, rather than skipping it silently. They say how to track its files, keep it as a subrepo, or leave it out.
  • oxy rebase CHANGE --onto T --into-working-copy. Where a rebase would be conflicted, the target is merged into the current bookmark instead, and the conflict is resolved in the working copy, as after oxy merge.
  • mimalloc is the allocator. Most of the speed above came from it: status, walks and index loads allocate many small values from every thread.
  • Internals. Each item below is a cache and is rebuilt when it does not check:
    • the workspace manifest is a checksummed binary file;
    • the state index is decoded lazily, caught up by replaying a few changes, and kept for the last two states;
    • the store caches change metadata;
    • a pack can carry a trained zstd dictionary.

0.1.0 (2026-09-30)

  • The first builds for people to download.

    • Linux x86_64 and arm64 (glibc 2.28 or later) as .tar.gz and .deb.
    • macOS x86_64 and arm64.
    • Windows x86_64.

    All are cross-compiled from Linux with scripts/dist.sh, with SHA256SUMS. A prerelease: formats may still change before 1.0.