git_branches/
lib.rs

1mod branch;
2mod rebase;
3mod render;
4
5pub use branch::{BranchInfo, Node, Topology};
6pub use render::render;
7
8use grit::trunk;
9
10/// Collect branch topology data for the current repository.
11///
12/// # Errors
13///
14/// Returns an error if trunk detection or git operations fail.
15pub async fn topology() -> Result<Topology, Error> {
16    let trunk = trunk::local().await.map_err(Error::Trunk)?;
17    branch::collect(&trunk).await.map_err(Error::Git)
18}
19
20/// Rebase a branch and all its descendants onto trunk.
21///
22/// # Errors
23///
24/// Returns an error if the branch is not found, or if git operations fail.
25pub async fn rebase(branch_name: &str) -> Result<(), Error> {
26    let trunk = trunk::local().await.map_err(Error::Trunk)?;
27    let topology = branch::collect(&trunk).await.map_err(Error::Git)?;
28
29    // Find the node containing the branch in the topology tree.
30    let Some(node) = find_branch_node(&topology.root, branch_name) else {
31        return Err(Error::BranchNotFound(branch_name.to_owned()));
32    };
33
34    rebase::rebase_stack(&trunk, node).await.map_err(Error::Git)
35}
36
37/// Find a node by branch name in the tree.
38fn find_branch_node<'a>(node: &'a Node, name: &str) -> Option<&'a Node> {
39    // Check if this node contains the branch we're looking for.
40    if node.branches.iter().any(|info| info.name == name) {
41        return Some(node);
42    }
43
44    // Search children.
45    for child in &node.children {
46        if let Some(found) = find_branch_node(child, name) {
47            return Some(found);
48        }
49    }
50
51    None
52}
53
54#[derive(Debug)]
55pub enum Error {
56    Trunk(trunk::Error),
57    Git(grit::git::Error),
58    BranchNotFound(String),
59}
60
61impl std::fmt::Display for Error {
62    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63        match self {
64            Error::Trunk(e) => write!(f, "{e}"),
65            Error::Git(e) => write!(f, "{e}"),
66            Error::BranchNotFound(name) => write!(f, "branch not found: {name}"),
67        }
68    }
69}