Skip to main content

git_rewrite/
exe.rs

1use git2 as git;
2
3/// Arguments for the `tree` subcommand.
4///
5/// Defined here so that the library exposes a self-contained type that
6/// downstream code can construct directly without going through the CLI.
7#[derive(clap::Args, Clone)]
8pub struct TreeArgs {
9    /// Tree-ish reference (commit, branch, tag, or tree SHA).
10    #[arg(default_value = "HEAD")]
11    pub treeish: String,
12
13    /// Glob patterns for entries to keep in the tree (may be repeated).
14    #[arg(long = "only", required = true)]
15    pub patterns: Vec<String>,
16
17    /// Allow running with uncommitted changes in the working tree.
18    #[arg(long)]
19    pub allow_dirty: bool,
20}
21
22pub fn tree(args: &TreeArgs) -> Result<(), Box<dyn std::error::Error>> {
23    let repo = git::Repository::open_from_env()?;
24
25    if !args.allow_dirty {
26        let statuses = repo.statuses(Some(
27            git::StatusOptions::new()
28                .include_untracked(false)
29                .include_ignored(false),
30        ))?;
31        if !statuses.is_empty() {
32            return Err(
33                "working tree has uncommitted changes; use --allow-dirty to override".into(),
34            );
35        }
36    }
37
38    let tree_oid = git_filter_tree::exe::filter_tree(&repo, &args.treeish, &args.patterns)?;
39    let filtered = repo.find_tree(tree_oid)?;
40
41    let mut index = repo.index()?;
42    index.read_tree(&filtered)?;
43    index.write()?;
44
45    let pattern_list: String = args
46        .patterns
47        .iter()
48        .map(|p| format!("'{}'", p))
49        .collect::<Vec<_>>()
50        .join(", ");
51
52    println!(
53        "Rewrote {} keeping only {} and updated the index ({} entries).",
54        args.treeish,
55        pattern_list,
56        filtered.len(),
57    );
58
59    Ok(())
60}