eazygit 0.5.1

A fast TUI for Git with staging, conflicts, rebase, and palette-first UX
Documentation
//! Remote operations: push, fetch, remote_url, set_remote_url, remote_prune, ahead_behind.

use anyhow::{bail, Result};
use std::process::Command;
use super::GitCli;

impl GitCli {
    /// Push current branch.
    pub fn push(&self, repo_path: &str, force_with_lease: bool) -> Result<()> {
        let mut cmd = Command::new("git");
        cmd.args(["-C", repo_path, "push"]);
        if force_with_lease { cmd.arg("--force-with-lease"); }
        let output = cmd.output()?;
        if !output.status.success() {
            bail!("git push failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(())
    }

    /// Fetch remote refs (dry-run).
    pub fn fetch_dry_run(&self, repo_path: &str, remote: &str) -> Result<String> {
        let output = Command::new("git")
            .args(["-C", repo_path, "fetch", "--dry-run", remote])
            .output()?;
        if !output.status.success() {
            bail!("git fetch --dry-run failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(String::from_utf8_lossy(&output.stdout).into_owned())
    }

    /// Get ahead/behind against a remote branch.
    pub fn ahead_behind_remote(&self, repo_path: &str, branch: &str) -> Result<(i32, i32)> {
        let rev = format!("origin/{}", branch);
        let output = Command::new("git")
            .args(["-C", repo_path, "rev-list", "--left-right", "--count", &format!("{}...{}", rev, branch)])
            .output()?;
        if !output.status.success() {
            bail!("git rev-list failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        let text = String::from_utf8_lossy(&output.stdout).to_string();
        let parts: Vec<&str> = text.trim().split_whitespace().collect();
        if parts.len() >= 2 {
            Ok((parts[1].parse().unwrap_or(0), parts[0].parse().unwrap_or(0)))
        } else {
            bail!("unexpected rev-list output");
        }
    }

    /// Remote prune stale tracking branches.
    pub fn remote_prune(&self, repo_path: &str, remote: &str) -> Result<String> {
        let output = Command::new("git")
            .args(["-C", repo_path, "remote", "prune", remote])
            .output()?;
        if !output.status.success() {
            bail!("git remote prune failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(String::from_utf8_lossy(&output.stdout).into_owned())
    }

    /// Get remote URL.
    pub fn remote_url(&self, repo_path: &str, remote: &str) -> Result<String> {
        let output = Command::new("git")
            .args(["-C", repo_path, "remote", "get-url", remote])
            .output()?;
        if !output.status.success() {
            bail!("git remote get-url failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
    }

    /// Set remote URL.
    pub fn set_remote_url(&self, repo_path: &str, remote: &str, url: &str) -> Result<()> {
        let output = Command::new("git")
            .args(["-C", repo_path, "remote", "set-url", remote, url])
            .output()?;
        if !output.status.success() {
            bail!("git remote set-url failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(())
    }
}