git_snip/
lib.rs

1mod branch;
2mod hook;
3mod input;
4mod reference;
5mod remote;
6mod repo;
7
8use std::env;
9
10use anyhow::{Context, Result};
11
12use hook::{GitHook, GitHookType};
13
14/// Delete all local branches that are not in remote branches.
15pub fn run(no_confirm: bool, install_hook: bool) -> Result<()> {
16    // Get current working directory
17    let current_dir = env::current_dir().context("Could not get current directory")?;
18    let repo = repo::Repository::open(current_dir)?;
19
20    // Install the hook script if requested.
21    if install_hook {
22        println!("Installing git-snip hook script.");
23        let hook = GitHook::default();
24        repo.install_hook(&hook, GitHookType::PostMerge)?;
25        repo.install_hook(&hook, GitHookType::PostRewrite)?;
26    }
27
28    let mut branches_to_delete = repo.orphaned_branches();
29    if branches_to_delete.is_empty() {
30        println!("No local branches to delete.");
31        return Ok(());
32    }
33
34    if !no_confirm {
35        println!("Local branches to delete:");
36        for branch in &branches_to_delete {
37            println!("  - {branch}");
38        }
39
40        let user_input = input::prompt_stdin("Delete these branches? (y/n): ");
41        if user_input != "y" && user_input != "yes" {
42            println!("Aborting.");
43            return Ok(());
44        }
45    }
46
47    for branch in &mut branches_to_delete {
48        println!("Deleting branch: {branch}");
49        branch.delete()?;
50    }
51
52    Ok(())
53}
54
55#[cfg(test)]
56pub mod test_utilities {
57    use git2::{Repository, RepositoryInitOptions};
58    use tempfile::TempDir;
59
60    /// Create a mock Git repository with initial commit in a temporary
61    /// directory for testing.
62    pub fn create_mock_repo() -> (TempDir, Repository) {
63        let tempdir = TempDir::new().unwrap();
64        let mut opts = RepositoryInitOptions::new();
65        opts.initial_head("main");
66        let repo = Repository::init_opts(tempdir.path(), &opts).unwrap();
67
68        // Create initial commit
69        {
70            let mut config = repo.config().unwrap();
71            config.set_str("user.name", "name").unwrap();
72            config.set_str("user.email", "email").unwrap();
73            let mut index = repo.index().unwrap();
74            let id = index.write_tree().unwrap();
75
76            let tree = repo.find_tree(id).unwrap();
77            let sig = repo.signature().unwrap();
78            repo.commit(Some("HEAD"), &sig, &sig, "initial\n\nbody", &tree, &[])
79                .unwrap();
80        }
81        (tempdir, repo)
82    }
83
84    /// Find the latest commit in a repository.
85    pub fn get_latest_commit(repo: &git2::Repository) -> git2::Commit {
86        let head = repo.head().unwrap();
87        let commit = head.peel_to_commit().unwrap();
88        commit
89    }
90}