git verify: --max-differences, and what differs by kind 8b7986dd3cb0
Verify stopped after 50 differences, so one carried through history (a tree conflict an older import left) used them up in the first commits and hid every later one: on VS Code the 400 commits being checked were never reached. --max-differences N sets the limit (0 checks every commit), and the end of the report counts the differences by kind. refs #80
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-10-09 02:58 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
8b7986dd3cb0152e7e433b24701abaea443209e81be3effd7cdcb6457431b5ce- Depends on
- 62794ecc7f74 79ab8528ff62 7eac74abc586 ee6aa3e81bc8 fce44ae9ad29
- Depended on by
- nothing yet
- In bookmarks
- 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.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
- 16 atoms, 0 tree operations, 3 files
Browse the tree at this change
modified crates/oxy-core/src/repo/git.rs +6 −3
| … | 1377 unchanged lines |
||
| 1378 | 1378 | /// for byte, with the same executable bits, symlink targets and |
|
| 1379 | 1379 | /// submodule pins. Reads only; stops listing after 50 differences. |
|
| 1380 | 1380 | pub fn verify_git_import(&self, git_dir: &Path, branch: &str) -> Result<GitVerifyReport> { |
|
| 1381 | - | self.verify_git_import_last(git_dir, branch, None) |
|
| 1381 | + | self.verify_git_import_last(git_dir, branch, None, 50) |
|
| 1382 | 1382 | } |
|
| 1383 | 1383 | ||
| 1384 | 1384 | /// [`Repo::verify_git_import`] of the last `last` commits only (all |
|
| 1385 | 1385 | /// when `None`): earlier ones are only followed, not rebuilt, for |
|
| 1386 | 1386 | /// looking again at where an import went wrong. |
|
| 1387 | + | /// It stops after `max` differences (0: never), so one that repeats |
|
| 1388 | + | /// through history does not hide the commits after it. |
|
| 1387 | 1389 | pub fn verify_git_import_last( |
|
| 1388 | 1390 | &self, |
|
| 1389 | 1391 | git_dir: &Path, |
|
| 1390 | 1392 | branch: &str, |
|
| 1391 | 1393 | last: Option<usize>, |
|
| 1394 | + | max: usize, |
|
| 1392 | 1395 | ) -> Result<GitVerifyReport> { |
|
| 1393 | 1396 | let commits = list_commits(git_dir, branch)?; |
|
| 1394 | 1397 | let imported = self.imported_commits()?; |
|
| … | 62 unchanged lines |
||
| 1457 | 1460 | if children.get(c.sha.as_str()).is_some_and(|n| *n > 0) { |
|
| 1458 | 1461 | closure.insert(c.sha.clone(), set.clone()); |
|
| 1459 | 1462 | } |
|
| 1460 | - | if rep.mismatches.len() >= 50 { |
|
| 1463 | + | if max > 0 && rep.mismatches.len() >= max { |
|
| 1461 | 1464 | break; |
|
| 1462 | 1465 | } |
|
| 1463 | 1466 | if last.is_some_and(|n| rep.commits + n <= commits.len()) { |
|
| … | 186 unchanged lines |
||
| 1650 | 1653 | } |
|
| 1651 | 1654 | } |
|
| 1652 | 1655 | } |
|
| 1653 | - | if rep.mismatches.len() >= 50 { |
|
| 1656 | + | if max > 0 && rep.mismatches.len() >= max { |
|
| 1654 | 1657 | break; |
|
| 1655 | 1658 | } |
|
| 1656 | 1659 | } |
|
| … | 28 unchanged lines |
modified src/cli/mod.rs +5 −1
| … | 809 unchanged lines |
||
| 810 | 810 | /// Rebuild only the last N commits (the others are followed, not checked) |
|
| 811 | 811 | #[arg(long, value_name = "N")] |
|
| 812 | 812 | last: Option<usize>, |
|
| 813 | + | /// Stop after N differences (0: check every commit whatever it finds) |
|
| 814 | + | #[arg(long, value_name = "N", default_value_t = 50)] |
|
| 815 | + | max_differences: usize, |
|
| 813 | 816 | }, |
|
| 814 | 817 | /// Import a Git branch into a new Oxygen repository at DEST |
|
| 815 | 818 | Import { |
|
| … | 338 unchanged lines |
||
| 1154 | 1157 | git_dir, |
|
| 1155 | 1158 | branch, |
|
| 1156 | 1159 | last, |
|
| 1160 | + | max_differences, |
|
| 1157 | 1161 | }, |
|
| 1158 | - | } => sync::git_verify(&git_dir, &branch, last), |
|
| 1162 | + | } => sync::git_verify(&git_dir, &branch, last, max_differences), |
|
| 1159 | 1163 | Cmd::Policy { cmd } => match cmd { |
|
| 1160 | 1164 | PolicyCmd::Init => identity::policy_init(), |
|
| 1161 | 1165 | PolicyCmd::Show { json } => identity::policy_show(json), |
|
| … | 67 unchanged lines |
modified src/cli/sync.rs +26 −4
| … | 501 unchanged lines |
||
| 502 | 502 | } |
|
| 503 | 503 | ||
| 504 | 504 | /// `oxy git verify`: exit 1 if any commit's tree is not reproduced. |
|
| 505 | - | pub fn git_verify(git_dir: &std::path::Path, branch: &str, last: Option<usize>) -> Result<i32> { |
|
| 505 | + | pub fn git_verify( |
|
| 506 | + | git_dir: &std::path::Path, |
|
| 507 | + | branch: &str, |
|
| 508 | + | last: Option<usize>, |
|
| 509 | + | max: usize, |
|
| 510 | + | ) -> Result<i32> { |
|
| 506 | 511 | let repo = open()?; |
|
| 507 | 512 | let started = std::time::Instant::now(); |
|
| 508 | 513 | let sp = ui::spinner(&format!( |
|
| 509 | 514 | "Rebuilding every commit of {} {branch}…", |
|
| 510 | 515 | git_dir.display() |
|
| 511 | 516 | )); |
|
| 512 | - | let r = repo.verify_git_import_last(git_dir, branch, last)?; |
|
| 517 | + | let r = repo.verify_git_import_last(git_dir, branch, last, max)?; |
|
| 513 | 518 | sp.clear(); |
|
| 514 | 519 | for (_, what) in &r.mismatches { |
|
| 515 | 520 | println!("{} {what}", ui::err(ui::glyph("✖", "x"))); |
|
| … | 20 unchanged lines |
||
| 536 | 541 | ); |
|
| 537 | 542 | Ok(0) |
|
| 538 | 543 | } else { |
|
| 544 | + | // What differs, by kind, the commit taken off: one difference |
|
| 545 | + | // carried through history reads as one line. |
|
| 546 | + | let mut kinds: std::collections::BTreeMap<String, usize> = Default::default(); |
|
| 547 | + | for (_, what) in &r.mismatches { |
|
| 548 | + | let kind = what.split_once(": ").map_or(what.as_str(), |(_, k)| k); |
|
| 549 | + | *kinds.entry(kind.to_string()).or_default() += 1; |
|
| 550 | + | } |
|
| 551 | + | let mut kinds: Vec<_> = kinds.into_iter().collect(); |
|
| 552 | + | kinds.sort_by_key(|k| std::cmp::Reverse(k.1)); |
|
| 553 | + | for (kind, n) in kinds.iter().take(10) { |
|
| 554 | + | println!(" {} {}", ui::dim(format!("{n:>6} ×")), kind); |
|
| 555 | + | } |
|
| 539 | 556 | println!( |
|
| 540 | - | "{} differences in {} commits checked", |
|
| 557 | + | "{} differences in {} commits checked{}", |
|
| 541 | 558 | r.mismatches.len(), |
|
| 542 | - | r.commits |
|
| 559 | + | r.commits, |
|
| 560 | + | if max > 0 && r.mismatches.len() >= max { |
|
| 561 | + | format!(" (stopped at {max}; --max-differences 0 checks every commit)") |
|
| 562 | + | } else { |
|
| 563 | + | String::new() |
|
| 564 | + | } |
|
| 543 | 565 | ); |
|
| 544 | 566 | Ok(1) |
|
| 545 | 567 | } |
|
| … | 217 unchanged lines |