securegit 0.8.5

Zero-trust git replacement with 12 built-in security scanners, LLM redteam bridge, universal undo, durable backups, and a 50-tool MCP server
Documentation
use crate::cli::UI;
use crate::ops::oplog;
use crate::ops::utils::short_oid;
use anyhow::{bail, Result};
use std::path::Path;

pub fn execute(
    path: &Path,
    commit_ref: &str,
    abort: bool,
    continue_revert: bool,
    skip: bool,
    no_commit: bool,
    ui: &UI,
) -> Result<()> {
    let desc = if abort {
        "abort revert".to_string()
    } else if continue_revert {
        "continue revert".to_string()
    } else if skip {
        "skip revert".to_string()
    } else {
        format!("revert {}", commit_ref)
    };
    oplog::with_oplog(path, "revert", &desc, || {
        execute_inner(
            path,
            commit_ref,
            abort,
            continue_revert,
            skip,
            no_commit,
            ui,
        )
    })
}

fn execute_inner(
    path: &Path,
    commit_ref: &str,
    abort: bool,
    continue_revert: bool,
    skip: bool,
    no_commit: bool,
    ui: &UI,
) -> Result<()> {
    let repo = crate::ops::open_repo(path)?;

    if abort {
        if repo.state() != git2::RepositoryState::RevertSequence
            && repo.state() != git2::RepositoryState::Revert
        {
            bail!("No revert in progress to abort.");
        }
        repo.cleanup_state()?;
        let head = repo.head()?.peel_to_commit()?;
        repo.reset(head.as_object(), git2::ResetType::Hard, None)?;
        ui.success("Revert aborted");
        return Ok(());
    }

    if skip {
        if repo.state() != git2::RepositoryState::RevertSequence
            && repo.state() != git2::RepositoryState::Revert
        {
            bail!("No revert in progress to skip.");
        }
        let head = repo.head()?.peel_to_commit()?;
        repo.reset(head.as_object(), git2::ResetType::Hard, None)?;
        repo.cleanup_state()?;
        ui.success("Revert skipped");
        return Ok(());
    }

    if continue_revert {
        if repo.state() != git2::RepositoryState::RevertSequence
            && repo.state() != git2::RepositoryState::Revert
        {
            bail!("No revert in progress to continue.");
        }
        let index = repo.index()?;
        if index.has_conflicts() {
            bail!("Conflicts still exist. Resolve them before continuing.");
        }
        let mut index = repo.index()?;
        let tree_oid = index.write_tree()?;
        let tree = repo.find_tree(tree_oid)?;
        let sig = repo.signature().map_err(|_| {
            anyhow::anyhow!(
                "Author identity not configured. Run:\n  \
                 git config user.name \"Your Name\"\n  \
                 git config user.email \"you@example.com\""
            )
        })?;
        let head_commit = repo.head()?.peel_to_commit()?;
        repo.commit(
            Some("HEAD"),
            &sig,
            &sig,
            "revert (continued)",
            &tree,
            &[&head_commit],
        )?;
        repo.cleanup_state()?;
        ui.success("Revert continued and committed");
        return Ok(());
    }

    let obj = repo.revparse_single(commit_ref)?;
    let commit = obj.peel_to_commit()?;

    repo.revert(&commit, None)?;

    let index = repo.index()?;
    if index.has_conflicts() {
        let hash = short_oid(&commit.id());
        let _ = crate::ops::conflicts::record_conflicts(path, &hash, "revert", commit_ref);
        ui.warning(format!("Revert of {} had conflicts", hash));
        ui.info("Resolve conflicts, then run: securegit revert --continue");
        ui.info("Or abort with: securegit revert --abort");
        return Ok(());
    }

    if no_commit {
        repo.cleanup_state()?;
        let hash = short_oid(&commit.id());
        ui.success(format!(
            "Revert of {} applied to index (not committed)",
            hash
        ));
        return Ok(());
    }

    // Auto-commit when clean
    let mut index = repo.index()?;
    let tree_oid = index.write_tree()?;
    let tree = repo.find_tree(tree_oid)?;
    let sig = repo.signature().map_err(|_| {
        anyhow::anyhow!(
            "Author identity not configured. Run:\n  \
             git config user.name \"Your Name\"\n  \
             git config user.email \"you@example.com\""
        )
    })?;
    let head_commit = repo.head()?.peel_to_commit()?;

    let msg = format!(
        "Revert \"{}\"\n\nThis reverts commit {}.",
        commit.summary().unwrap_or(""),
        commit.id()
    );
    match repo.commit(Some("HEAD"), &sig, &sig, &msg, &tree, &[&head_commit]) {
        Ok(_) => {
            repo.cleanup_state()?;
            let hash = short_oid(&commit.id());
            ui.success(format!(
                "Reverted [{}] \"{}\"",
                hash,
                commit.summary().unwrap_or("")
            ));
        }
        Err(e) => {
            let _ = repo.cleanup_state();
            bail!("Revert commit failed: {}", e);
        }
    }

    Ok(())
}