Skip to main content

git_workflow/commands/
abandon.rs

1//! `gw abandon` command - Abandon current changes and return to home branch
2
3use crate::error::{GwError, Result};
4use crate::git;
5use crate::output;
6use crate::state::{RepoType, SyncState, WorkingDirState};
7
8/// Execute the `abandon` 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    let repo_type = RepoType::detect()?;
16    let home_branch = repo_type.home_branch();
17    let current = git::current_branch()?;
18    let working_dir = WorkingDirState::detect();
19
20    println!();
21    output::info(&format!("Current branch: {}", output::bold(&current)));
22    output::info(&format!("Home branch: {}", output::bold(home_branch)));
23
24    // Check what will be affected
25    let has_changes = !working_dir.is_clean();
26    let has_untracked = git::has_untracked_files();
27    let sync_state = SyncState::detect(&current).unwrap_or(SyncState::NoUpstream);
28
29    // Already on home branch with clean working directory and no untracked files
30    if !has_changes && !has_untracked && current == home_branch {
31        output::success("Already on home branch with clean working directory");
32        // Still sync with origin/main
33        output::info("Syncing with origin/main...");
34        git::fetch_prune(verbose)?;
35        git::pull("origin", "main", verbose)?;
36        output::success("Synced");
37        return Ok(());
38    }
39
40    // Warn about what will be lost
41    if has_changes {
42        output::warn(&format!(
43            "Uncommitted changes will be DISCARDED: {}",
44            working_dir.description()
45        ));
46    }
47    if has_untracked {
48        output::warn("Untracked files will be DELETED");
49    }
50
51    // Warn about unpushed commits (they'll remain on the branch, not lost)
52    if let SyncState::HasUnpushedCommits { count } = sync_state {
53        output::warn(&format!(
54            "Branch '{}' has {} unpushed commit(s). They will remain on the branch.",
55            current, count
56        ));
57    }
58
59    // Discard changes if any (including untracked files)
60    if has_changes || has_untracked {
61        output::info("Discarding changes...");
62        git::discard_all_changes(verbose)?;
63        output::success("Changes discarded");
64    }
65
66    // Switch to home branch if not already there
67    if current != home_branch {
68        if !git::branch_exists(home_branch) {
69            output::info("Creating home branch from origin/main...");
70            git::checkout_new_branch(home_branch, "origin/main", verbose)?;
71        } else {
72            git::checkout(home_branch, verbose)?;
73        }
74        output::success(&format!("Switched to {}", output::bold(home_branch)));
75    }
76
77    // Sync with origin/main
78    output::info("Syncing with origin/main...");
79    git::fetch_prune(verbose)?;
80    git::pull("origin", "main", verbose)?;
81    output::success("Synced");
82
83    output::ready("Ready", home_branch);
84    output::hints(&["gw new feature/your-feature  # Start fresh"]);
85
86    Ok(())
87}