Skip to main content

git_workflow/commands/
undo.rs

1//! `gw undo` command - Undo the last commit (soft reset HEAD~1)
2
3use crate::error::{GwError, Result};
4use crate::git;
5use crate::output;
6use crate::state::SyncState;
7
8/// Execute the `undo` command
9pub fn run(verbose: bool) -> Result<()> {
10    // Ensure we're in a git repo
11    if !git::is_git_repo() {
12        return Err(GwError::NotAGitRepository);
13    }
14
15    // Check if we can undo
16    if !git::has_commits_to_undo() {
17        return Err(GwError::NothingToUndo);
18    }
19
20    let current = git::current_branch()?;
21
22    // Show what we're undoing
23    let commit_short = git::short_commit()?;
24    let commit_msg = git::head_commit_message()?;
25
26    println!();
27    output::info(&format!(
28        "Undoing commit: {} {}",
29        output::bold(&commit_short),
30        commit_msg
31    ));
32
33    // Check if commit was pushed (warn but continue)
34    let sync_state = SyncState::detect(&current).unwrap_or(SyncState::NoUpstream);
35    if matches!(sync_state, SyncState::Synced | SyncState::Behind { .. }) {
36        output::warn("This commit may have been pushed. Local undo won't affect remote.");
37        output::warn("You may need to force push after undoing.");
38    }
39
40    // Soft reset
41    git::reset_soft("HEAD~1", verbose)?;
42    output::success("Commit undone (changes are now staged)");
43
44    output::ready("Undone", &current);
45    output::hints(&[
46        "git status         # See staged changes",
47        "git diff --cached  # Review staged changes",
48        "git commit -m \"...\"  # Re-commit with new message",
49    ]);
50
51    Ok(())
52}