eazygit 0.5.1

A fast TUI for Git with staging, conflicts, rebase, and palette-first UX
Documentation
//! Branch management commands.
//!
//! Handles listing and pruning merged branches.

use crate::commands::{Command, CommandResult};
use crate::services::GitService;
use crate::app::{AppState, Action, reducer};
use crate::errors::CommandError;
use tracing::instrument;

/// List merged branches
pub struct ListMergedBranchesCommand {
    pub base: String,
}

impl Command for ListMergedBranchesCommand {
    #[instrument(skip(self, git, state), fields(base = %self.base))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetOpStatus(Some(format!("listing merged into {}", self.base))));
        match git.merged_local_branches(&state.repo_path, &self.base) {
            Ok(list) => {
                if list.is_empty() {
                    new_state = reducer(new_state, Action::AppendOpLog(format!("no merged branches into {}", self.base)));
                    new_state = reducer(new_state, Action::SetFeedback(Some("No merged branches".into())));
                } else {
                    new_state = reducer(new_state, Action::AppendOpLog(format!("merged into {}:", self.base)));
                    for b in list {
                        new_state = reducer(new_state, Action::AppendOpLog(format!("  {}", b)));
                    }
                }
            }
            Err(e) => {
                new_state = reducer(new_state, Action::AppendOpLog(format!("merged list error: {e}")));
                new_state = reducer(new_state, Action::SetStatusError(Some(format!("merged list error: {e}"))));
            }
        }
        new_state = reducer(new_state, Action::SetOpStatus(None));
        Ok(CommandResult::StateUpdate(new_state))
    }
}

/// Prune merged branches (after confirm)
pub struct PruneMergedBranchesCommand {
    pub base: String,
}

impl Command for PruneMergedBranchesCommand {
    #[instrument(skip(self, git, state), fields(base = %self.base))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetOpStatus(Some(format!("pruning merged into {}", self.base))));
        match git.merged_local_branches(&state.repo_path, &self.base) {
            Ok(list) => {
                if list.is_empty() {
                    new_state = reducer(new_state, Action::AppendOpLog(format!("no merged branches into {}", self.base)));
                    new_state = reducer(new_state, Action::SetFeedback(Some("No merged branches".into())));
                } else {
                    let mut pruned = 0;
                    for b in list {
                        match git.delete_local_branch(&state.repo_path, &b) {
                            Ok(_) => {
                                pruned += 1;
                                new_state = reducer(new_state, Action::AppendOpLog(format!("deleted {}", b)));
                            }
                            Err(e) => {
                                new_state = reducer(new_state, Action::AppendOpLog(format!("delete {} failed: {e}", b)));
                            }
                        }
                    }
                    new_state = reducer(new_state, Action::SetFeedback(Some(format!("Pruned {} branch(es)", pruned))));
                    new_state = reducer(new_state, Action::SetRefreshing(true));
                }
            }
            Err(e) => {
                new_state = reducer(new_state, Action::AppendOpLog(format!("prune error: {e}")));
                new_state = reducer(new_state, Action::SetStatusError(Some(format!("prune error: {e}"))));
            }
        }
        new_state = reducer(new_state, Action::SetOpStatus(None));
        Ok(CommandResult::StateUpdate(new_state))
    }
}