Skip to main content

mkit_cli/commands/
rev_list.rs

1//! `mkit rev-list [--count] <rev>` — list the commit ids reachable from
2//! `<rev>` in reverse-chronological (topological) order, or just their
3//! count. Reuses `log`'s ordered walk so ordering matches `mkit log`.
4//! Object ids are full 64-hex BLAKE3 (the documented divergence).
5
6use std::collections::HashSet;
7use std::io::Write;
8
9use clap::Parser;
10use mkit_core::store::ObjectStore;
11
12use crate::clap_shim;
13use crate::exit;
14use crate::format;
15
16#[derive(Debug, Parser)]
17#[command(
18    name = "mkit rev-list",
19    about = "List commit objects reachable from a revision."
20)]
21struct RevListOpts {
22    /// Print the number of commits instead of the list.
23    #[arg(long)]
24    count: bool,
25    /// Starting revision (branch / tag / commit / HEAD).
26    rev: String,
27}
28
29#[must_use]
30pub fn run(args: &[String]) -> u8 {
31    let opts = match clap_shim::parse::<RevListOpts>("mkit rev-list", args) {
32        Ok(o) => o,
33        Err(code) => return code,
34    };
35    let cwd = match std::env::current_dir() {
36        Ok(p) => p,
37        Err(e) => return emit_err(&format!("cwd: {e}"), exit::NOINPUT),
38    };
39    let layout = match super::resolve_layout(&cwd) {
40        Ok(layout) => layout,
41        Err(code) => return code,
42    };
43    let store = match ObjectStore::open(&layout) {
44        Ok(s) => s,
45        Err(e) => return emit_err(&format!("not a mkit repo: {e}"), exit::GENERAL_ERROR),
46    };
47    let tip = match super::revspec::resolve_revision(&store, &layout, &opts.rev) {
48        // Peel annotated/signed tags to the commit they point at, like
49        // `log`/`diff`/`branch` (resolve_revision returns the tag object).
50        Ok(h) => super::log::peel_tags(&store, h),
51        Err(e) => {
52            return emit_err(
53                &format!("bad revision '{}': {e}", opts.rev),
54                exit::GENERAL_ERROR,
55            );
56        }
57    };
58    let commits = match super::log::ordered_commits(&store, &[tip], &HashSet::new()) {
59        Ok(c) => c,
60        Err(code) => return code,
61    };
62    let mut stdout = std::io::stdout().lock();
63    if opts.count {
64        let _ = writeln!(stdout, "{}", commits.len());
65    } else {
66        for (h, _) in &commits {
67            let _ = writeln!(stdout, "{}", format::hex_hash(h));
68        }
69    }
70    exit::OK
71}
72
73use super::error as emit_err;