OXYGENHUB

oxy log shows the working copy as last recorded, and takes milliseconds (refs #41) 33472ccc08cc

Log spent all its time (163 ms on the Linux tree, 0.4 ms for the entries)
checking the files on disk to label the working-copy row clean. It now
describes the working copy as last recorded: its change's edits, and the
manifest's conflict flag (Repo::recorded_conflicted), as Git's log never
looks at the working tree; oxy status checks the disk. log -n 100: Linux
tree 0.03 s (from 0.17 s), oxygen 0.03 s and 22 MB (from 0.06 s, 79 MB),
a 10 000-commit vscode slice 0.02 s.
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-01 23:04 UTC
Signature
✔ signed by Andy McCall
Hash
33472ccc08ccc78ba9a8ce05bbc251148e66b06d2087e930f07cdef8682e3129
Depends on
135212de5370 1d360c91a289 2bf22305bc48 4cce912a0953 69816d688300 75167672ebcd 8fd78eb52ad2 94084087a876 98a1620a3840 c07406bcc237 cd4eb55e3b3d d0990c2bff74 e226a6cc2f71 ee06a6c557b7 fce44ae9ad29
Depended on by
fddf64baa3d2 5ae7533f1888
In bookmarks
agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
In tags
v0.10.0 v0.11.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
Edits
9 atoms, 0 tree operations, 5 files

Browse the tree at this change

modified CHANGELOG.md +2 −0
…
1 unchanged lines
2 2
3 3
## Unreleased
4 4
5 +
- **`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.
6 +
5 7
- **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.
6 8
7 9
- **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.
…
54 unchanged lines
modified crates/oxy-core/src/repo/prompt.rs +6 −0
…
469 unchanged lines
470 470
471 471
    /// The manifest, with whether it records a conflict and uncommitted
472 472
    /// work; parsed once while the file stays the same one.
473 +
    /// Whether the working copy was conflicted when last recorded (the
474 +
    /// manifest's flag), without looking at the files.
475 +
    pub fn recorded_conflicted(&self) -> Result<bool> {
476 +
        Ok(self.read_manifest()?.is_some_and(|(c, _, _)| c))
477 +
    }
478 +
473 479
    pub(crate) fn read_manifest(&self) -> Result<Option<(bool, bool, std::sync::Arc<Manifest>)>> {
474 480
        let path = self.manifest_path();
475 481
        let id = match fs::metadata(&path) {
…
489 unchanged lines
modified docs/benchmarks.md +15 −0
…
832 unchanged lines
833 833
new builds alternating, six direct commits each (load average 4.4): median
834 834
0.61 s before, 0.58 s after (Git 0.16 to 0.27 s at that load).
835 835
836 +
### log -n 100 (2026-10-02, oxygen#41)
837 +
838 +
`oxy log` no longer checks the files on disk: its working-copy row
839 +
describes the working copy as last recorded (with edits, or not; the
840 +
manifest's conflict flag), as Git's log never looks at the working tree.
841 +
The entries come from the state index's change metadata.
842 +
843 +
| repository | before | after | Git |
844 +
|---|---:|---:|---:|
845 +
| Linux tree (Earth) | 0.17 s | **0.03 s** | 0.00 s |
846 +
| oxygen, 388 changes (workstation) | 0.06 s, 79 MB | **0.03 s, 22 MB** | |
847 +
| vscode slice, 10 000 commits (Earth, warm) | | **0.02 s** | |
848 +
849 +
What remains on oxygen is checking each row's signature (30 ms for 100).
850 +
modified docs/guide.md +1 −1
…
67 unchanged lines
68 68
69 69
```
70 70
◉  2f8518c0 Andy McCall just now
71 -
│  (working copy, clean)
71 +
│  (working copy)
72 72
●  1b5888b1 Andy McCall 2 minutes ago main #cc23b999 ✔ signed
73 73
│  Edit b
74 74
│ ●  d6f52eca Andy McCall 3 minutes ago main #ec6a7dc4 ✔ signed
…
539 unchanged lines
modified src/cli/workspace.rs +11 −9
…
565 unchanged lines
566 566
    let repo = open()?;
567 567
    // Whether the working copy is clean and conflicted: from the manifest
568 568
    // when it proves the working copy clean, else from a snapshot.
569 -
    let (conflicted, clean) = if repo.is_at_op() || repo.clean_by_manifest()? {
570 -
        (false, true)
571 -
    } else {
572 -
        let snap = repo.snapshot_status("oxy log")?;
573 -
        (snap.base_snapshot.is_conflicted(), snap.statuses.is_empty())
574 -
    };
569 +
    // The working copy as last recorded, without looking at the files (as
570 +
    // Git's log does not): whether its change holds edits, and whether its
571 +
    // base was conflicted. `oxy status` is what checks the disk.
572 +
    let conflicted = !repo.is_at_op() && repo.recorded_conflicted()?;
575 573
    let listing = oxy_core::timing::phase("log: entries");
576 574
    let entries = match (path, lines) {
577 575
        (_, Some(spec)) => {
…
67 unchanged lines
645 643
        }
646 644
        println!("{}{}", node_line(row, &bullet), head.join(" "));
647 645
        let subject = if e.is_working_copy && c.message.is_empty() {
648 -
            ui::dim(if clean {
649 -
                "(working copy, clean)"
650 -
            } else {
646 +
            let edited = repo
647 +
                .store()
648 +
                .get_change(&e.hash)
649 +
                .is_ok_and(|w| !w.tree_ops.is_empty() || !w.edits.is_empty());
650 +
            ui::dim(if edited {
651 651
                "(working copy, uncommitted changes)"
652 +
            } else {
653 +
                "(working copy)"
652 654
            })
653 655
        } else if c.message.trim().is_empty() {
654 656
            ui::dim("(no description)")
…
1716 unchanged lines