eazygit 0.5.1

A fast TUI for Git with staging, conflicts, rebase, and palette-first UX
Documentation
//! Rebase operations: rebase_continue, rebase_abort, rebase_skip.

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

/// Convert RebaseEntry to git-rebase-todo format line
pub(crate) fn format_rebase_todo_line(action: &str, hash: &str, message: &str) -> String {
    format!("{} {} {}", action, hash, message)
}

/// Format multiple rebase entries into git-rebase-todo format
pub(crate) fn format_rebase_todo(entries: &[(String, String, String)]) -> String {
    // Format: "action hash message"
    entries
        .iter()
        .map(|(action, hash, message)| format_rebase_todo_line(action, hash, message))
        .collect::<Vec<_>>()
        .join("\n")
}

/// Write rebase todo file to disk
pub(crate) fn write_rebase_todo_file(path: &Path, content: &str) -> Result<()> {
    // Ensure parent directory exists
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(path, content)?;
    Ok(())
}

impl GitCli {
    /// Continue an in-progress rebase with optional message/author.
    pub fn rebase_continue(
        &self,
        repo_path: &str,
        message: Option<&str>,
        author_name: Option<&str>,
        author_email: Option<&str>,
    ) -> Result<()> {
        if let Some(msg) = message {
            let mut amend_cmd = Command::new("git");
            amend_cmd.args(["-C", repo_path, "commit", "--amend", "--allow-empty", "-m", msg]);
            if let Some(name) = author_name {
                amend_cmd.env("GIT_AUTHOR_NAME", name).env("GIT_COMMITTER_NAME", name);
            }
            if let Some(email) = author_email {
                amend_cmd.env("GIT_AUTHOR_EMAIL", email).env("GIT_COMMITTER_EMAIL", email);
            }
            let amend_output = amend_cmd.output()?;
            if !amend_output.status.success() {
                let stderr = String::from_utf8_lossy(&amend_output.stderr);
                if !stderr.contains("nothing to commit") && !stderr.contains("no rebase in progress") {
                    bail!("git commit --amend failed: {}", stderr);
                }
            }
        }
        
        let mut cmd = Command::new("git");
        cmd.args(["-C", repo_path, "rebase", "--continue"]);
        if let Some(name) = author_name { cmd.env("GIT_AUTHOR_NAME", name).env("GIT_COMMITTER_NAME", name); }
        if let Some(email) = author_email { cmd.env("GIT_AUTHOR_EMAIL", email).env("GIT_COMMITTER_EMAIL", email); }
        cmd.env("GIT_EDITOR", "true");
        
        let output = cmd.output()?;
        if !output.status.success() {
            bail!("git rebase --continue failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(())
    }

    /// Abort an in-progress rebase.
    pub fn rebase_abort(&self, repo_path: &str) -> Result<()> {
        let output = Command::new("git")
            .args(["-C", repo_path, "rebase", "--abort"])
            .output()?;
        if !output.status.success() {
            bail!("git rebase --abort failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(())
    }

    /// Skip current step in an in-progress rebase.
    pub fn rebase_skip(&self, repo_path: &str) -> Result<()> {
        let output = Command::new("git")
            .args(["-C", repo_path, "rebase", "--skip"])
            .output()?;
        if !output.status.success() {
            bail!("git rebase --skip failed: {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(())
    }
}