git_workflow/git/
mutation.rs1use std::process::Command;
4
5use crate::error::{GwError, Result};
6use crate::output;
7
8fn git_run(args: &[&str], verbose: bool) -> Result<()> {
10 if verbose {
11 output::action(&format!("git {}", args.join(" ")));
12 }
13
14 let output = Command::new("git")
15 .args(args)
16 .output()
17 .map_err(|e| GwError::GitCommandFailed(format!("Failed to execute git: {e}")))?;
18
19 if output.status.success() {
20 Ok(())
21 } else {
22 let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
23 Err(GwError::GitCommandFailed(stderr))
24 }
25}
26
27fn git_output(args: &[&str], verbose: bool) -> Result<String> {
29 if verbose {
30 output::action(&format!("git {}", args.join(" ")));
31 }
32
33 let output = Command::new("git")
34 .args(args)
35 .output()
36 .map_err(|e| GwError::GitCommandFailed(format!("Failed to execute git: {e}")))?;
37
38 if output.status.success() {
39 Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
40 } else {
41 let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
42 Err(GwError::GitCommandFailed(stderr))
43 }
44}
45
46pub fn fetch_prune(verbose: bool) -> Result<()> {
48 git_run(&["fetch", "--prune", "--quiet"], verbose)
49}
50
51pub fn checkout(branch: &str, verbose: bool) -> Result<()> {
53 git_run(&["checkout", branch, "--quiet"], verbose)
54}
55
56pub fn checkout_new_branch(branch: &str, start_point: &str, verbose: bool) -> Result<()> {
58 git_run(&["checkout", "-b", branch, start_point, "--quiet"], verbose)
59}
60
61pub fn pull_ff_only(remote: &str, branch: &str, verbose: bool) -> Result<()> {
66 git_run(&["pull", remote, branch, "--ff-only", "--quiet"], verbose)
67}
68
69pub fn pull(remote: &str, branch: &str, verbose: bool) -> Result<()> {
71 let result = git_run(&["pull", remote, branch, "--ff-only", "--quiet"], verbose);
73 if result.is_err() {
74 git_run(&["pull", remote, branch, "--quiet"], verbose)?;
76 }
77 Ok(())
78}
79
80pub fn delete_branch(branch: &str, verbose: bool) -> Result<()> {
82 git_run(&["branch", "-d", branch], verbose)
83}
84
85pub fn force_delete_branch(branch: &str, verbose: bool) -> Result<()> {
87 git_run(&["branch", "-D", branch], verbose)
88}
89
90#[allow(dead_code)]
92pub fn delete_remote_branch(branch: &str, verbose: bool) -> Result<()> {
93 git_run(&["push", "origin", "--delete", branch], verbose)
94}
95
96pub fn log_commits(from: &str, to: &str, verbose: bool) -> Result<Vec<String>> {
98 let output = git_output(&["log", &format!("{from}..{to}"), "--oneline"], verbose)?;
99 Ok(output.lines().map(String::from).collect())
100}
101
102pub fn add_all(verbose: bool) -> Result<()> {
104 git_run(&["add", "-A"], verbose)
105}
106
107pub fn commit(message: &str, verbose: bool) -> Result<()> {
109 git_run(&["commit", "-m", message], verbose)
110}
111
112pub fn reset_soft(target: &str, verbose: bool) -> Result<()> {
114 git_run(&["reset", "--soft", target], verbose)
115}
116
117pub fn discard_all_changes(verbose: bool) -> Result<()> {
119 git_run(&["reset", "--hard", "HEAD"], verbose)?;
121 git_run(&["clean", "-fd"], verbose)
123}
124
125pub fn rebase(target: &str, verbose: bool) -> Result<()> {
127 git_run(&["rebase", target], verbose)
128}
129
130pub fn force_push_with_lease(branch: &str, verbose: bool) -> Result<()> {
132 git_run(&["push", "--force-with-lease", "origin", branch], verbose)
133}