OXYGENHUB

Diff renders only the edited files and skips freeing at exit (refs #41) 10b4fd430eab

State::materialize_nodes renders the text files of the given nodes
without building a set of every other file to leave out, used for a
change's base; oxy diff forgets its structures as the process ends.
Phases for the base rendering and the diff rendering. On the Linux tree,
one file edited: 0.19 to 0.21 s (from 0.25 s; Git 0.08 s).
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-01 20:08 UTC
Signature
✔ signed by Andy McCall
Hash
10b4fd430eab7b04550857d897023a1338c85a754af46e59723a2a51dbc3e4ca
Depends on
1d360c91a289 1ec3f008e96a 77445673174b 8ab265dc4a51 8fd78eb52ad2 982864068a59 c07406bcc237 d616faf5d136 fce44ae9ad29 ff0af1ee299d
Depended on by
c2e1d09047db 74b4a3c62ea4 e226a6cc2f71
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 +1 −1
…
1 unchanged lines
2 2
3 3
## Unreleased
4 4
5 -
- **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.25 s, from 0.41 s). A file written within the racy window is now hashed by the prompt's check too, as it was by status.
5 +
- **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 file written within the racy window is now hashed by the prompt's check too, as it was by status.
6 6
7 7
- **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.
8 8
…
53 unchanged lines
modified crates/oxy-core/src/repo/mod.rs +5 −9
…
1969 unchanged lines
1970 1970
        change: &Change,
1971 1971
        mut base: State,
1972 1972
    ) -> Result<(State, Snapshot)> {
1973 +
        let _t = crate::timing::phase("diff: render the base");
1973 1974
        let edited: std::collections::HashSet<NodeId> =
1974 1975
            change.edits.iter().map(|e| e.node()).collect();
1975 1976
        let nodes: Vec<NodeId> = edited.iter().copied().collect();
1976 1977
        self.load_graphs_of(&mut base, &nodes)?;
1977 -
        let skip: std::collections::HashSet<NodeId> = base
1978 -
            .tree()
1979 -
            .view()
1980 -
            .entries
1981 -
            .values()
1982 -
            .filter(|e| e.kind == crate::objects::NodeKind::File && !edited.contains(&e.node))
1983 -
            .map(|e| e.node)
1984 -
            .collect();
1985 -
        let snapshot = base.materialize_except(&skip);
1978 +
        let snapshot = {
1979 +
            let _t = crate::timing::phase("diff:   of which materialize");
1980 +
            base.materialize_nodes(&edited)
1981 +
        };
1986 1982
        Ok((base, snapshot))
1987 1983
    }
1988 1984
}
…
116 unchanged lines
modified crates/oxy-core/src/state.rs +7 −0
…
1692 unchanged lines
1693 1693
        self.materialize_leaving(|p, _| !render.contains(p))
1694 1694
    }
1695 1695
1696 +
    /// As [`State::materialize_except`], rendering only the text files of
1697 +
    /// the nodes in `render` (a change's edited files), without a set of
1698 +
    /// every other file to leave out.
1699 +
    pub fn materialize_nodes(&self, render: &HashSet<NodeId>) -> Snapshot {
1700 +
        self.materialize_leaving(|_, e| !render.contains(&e.node))
1701 +
    }
1702 +
1696 1703
    fn materialize_leaving(
1697 1704
        &self,
1698 1705
        leave: impl Fn(&str, &crate::tree::TreeEntry) -> bool + Sync,
…
810 unchanged lines
modified docs/benchmarks.md +7 −0
…
790 unchanged lines
791 791
| status, clean | 0.15 to 0.21 s | **0.09 to 0.12 s, 80 MB** | 0.20 to 0.26 s |
792 792
| diff, one file | 0.34 s | 0.24 to 0.25 s | 0.09 to 0.13 s |
793 793
794 +
Diff, last round (load average 2.7): a change's base renders only its
795 +
edited files without first building a set of every other file to leave
796 +
out, and `oxy diff` no longer frees its structures just before the
797 +
process ends. 0.19 to 0.21 s (from 0.25 s; Git 0.08 s). What remains:
798 +
the stat check 78 ms (Git stats the same files), the state index 58 ms
799 +
(39 of them building the tree view), the base's full file map 21 ms.
800 +
modified src/cli/workspace.rs +8 −1
…
884 unchanged lines
885 885
        }
886 886
        None => {
887 887
            let (wc, base, snapshot) = repo.working_copy_with_base()?;
888 -
            print!("{}", render_change(&wc, &base, &snapshot));
888 +
            let text = {
889 +
                let _t = oxy_core::timing::phase("diff: render the change");
890 +
                render_change(&wc, &base, &snapshot)
891 +
            };
892 +
            print!("{text}");
893 +
            // The process ends here: freeing the base's tree and graphs
894 +
            // one by one would only cost time (about 27 ms on Linux).
895 +
            std::mem::forget((wc, base, snapshot));
889 896
        }
890 897
    }
891 898
    Ok(0)
…
1472 unchanged lines