OXYGENHUB

Switch and checkout name the files they take off disk 9b723f69b032

oxy bookmark switch and oxy checkout said only how many files they
removed, easy to miss when a switch to a bookmark lacking 80 files took
an editor's project file with them. They now name the first few removed
files, and warn when twenty or more go.

closes #102
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-12 00:14 UTC
Signature
✔ signed by Andy McCall
Hash
9b723f69b032497c1d66ac344c7075d163154bece2c0b6dd80037623f1a434c1
Depends on
34fad4a92451 4dee277c327a 75167672ebcd 7b9809e67c3d 8fd78eb52ad2 982864068a59 b689779e9e74 c5ce0367eddf d4dbab97e948 fce44ae9ad29
Depended on by
44f1ebe7aa5b ebb9210bad0c
In bookmarks
bare-hashes carried-not-removed 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.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
7 atoms, 0 tree operations, 4 files

Browse the tree at this change

modified CHANGELOG.md +2 −0
…
1 unchanged lines
2 2
3 3
## Unreleased
4 4
5 +
- **A switch names what it takes off disk (#102).** `oxy bookmark switch` and `oxy checkout` printed only how many files they removed, easy to miss when a switch to a bookmark lacking 80 files took an editor's project file with them. They now name the first few removed files, with a warning when twenty or more go.
6 +
5 7
- **Large new files are not snapshotted unseen, and past snapshots expire (#98).** A 1 GB image left untracked in a working tree was taken in by the next `status` and kept by the operation log for good: deleting the file and running `gc --now` freed nothing. Now a new, untracked file over `snapshot.max-new-file-size` (default 100 MiB) is left out and named by `status`, with how to ignore it or raise the limit; tracked files and files already in the working copy are unaffected. Past working-copy snapshots keep their files only for `core.snapshot-retention` (default 7 days), so `gc` prunes what only they held, and `oxy gc --expire-snapshots --now` does it at once. `undo` and `op restore` to an operation whose working copy has expired keep the files as they are.
6 8
7 9
- **`oxy undo` undoes this workspace's last command (#99).** It undid the repository's newest operation, whichever workspace made it: in a repository with several workspaces an undo could take back another workspace's commit or merge, and it said only which operation it went back to. Operations now record their workspace, and undo takes back this workspace's last command, leaving other workspaces' work as it is. On a bookmark both share, only its own heads go; a change another workspace built on it, or the workspace it would take away, refuses the undo and names it. Undo now says which command it undid and what that changed, passes over pushes (the remote keeps what it was sent), and warns when an undone commit is already on a remote. `oxy amend` warns when it rewrites a change a remote already has, so the next push will need `--force`.
…
172 unchanged lines
modified crates/oxy-core/src/repo/checkout.rs +5 −0
…
5 unchanged lines
6 6
pub struct CheckoutReport {
7 7
    pub written: usize,
8 8
    pub removed: usize,
9 +
    /// The first files removed, to name them (oxygen#102).
10 +
    pub removed_paths: Vec<String>,
9 11
    pub conflicted: bool,
10 12
    /// Nested repositories that could not be moved, and other remarks.
11 13
    pub notes: Vec<String>,
…
84 unchanged lines
96 98
            }
97 99
            fs::remove_file(&full)?;
98 100
            report.removed += 1;
101 +
            if report.removed_paths.len() < 5 {
102 +
                report.removed_paths.push(path.to_string());
103 +
            }
99 104
            if let Some(parent) = full.parent() {
100 105
                dirs_to_prune.insert(parent.to_path_buf());
101 106
            }
…
535 unchanged lines
modified crates/oxy-core/src/repo/tests.rs +1 −0
…
431 unchanged lines
432 432
        CheckoutReport {
433 433
            written: 2,
434 434
            removed: 1,
435 +
            removed_paths: vec!["bin.dat".into()],
435 436
            conflicted: false,
436 437
            notes: vec![],
437 438
            lacks: 1,
…
8084 unchanged lines
modified src/cli/workspace.rs +30 −0
…
98 unchanged lines
99 99
    );
100 100
}
101 101
102 +
/// Name what a checkout removed from the working copy (oxygen#102): a
103 +
/// switch to a bookmark lacking files takes them off disk, which an
104 +
/// editor open on the tree notices before a person reading a count does.
105 +
fn print_removed(r: &oxy_core::repo::CheckoutReport) {
106 +
    if r.removed == 0 {
107 +
        return;
108 +
    }
109 +
    let more = r.removed.saturating_sub(r.removed_paths.len());
110 +
    let names = r.removed_paths.join(", ");
111 +
    let tail = if more > 0 {
112 +
        format!(" and {more} more")
113 +
    } else {
114 +
        String::new()
115 +
    };
116 +
    let lead = if r.removed >= 20 {
117 +
        ui::caution()
118 +
    } else {
119 +
        ui::note()
120 +
    };
121 +
    println!(
122 +
        "  {} {}",
123 +
        lead,
124 +
        ui::dim(format!(
125 +
            "removed from disk (the bookmark does not have them): {names}{tail}"
126 +
        ))
127 +
    );
128 +
}
129 +
102 130
/// Folders holding a repository of their own, which oxy leaves out (oxygen#43):
103 131
/// named, with how to track them.
104 132
fn print_untracked_nested(repo: &Repo, nested: &[String]) {
…
1212 unchanged lines
1317 1345
            format!("; carried {}", plural(carried.len(), "changed path"))
1318 1346
        }
1319 1347
    ));
1348 +
    print_removed(&r);
1320 1349
    for n in &r.notes {
1321 1350
        println!("  {} {n}", ui::note());
1322 1351
    }
…
1406 unchanged lines
2729 2758
            format!("; carried {}", plural(carried.len(), "changed path"))
2730 2759
        }
2731 2760
    ));
2761 +
    print_removed(&r);
2732 2762
    if r.conflicted {
2733 2763
        println!(
2734 2764
            "  {} {}",
…
166 unchanged lines