Skip to main content

thor_wt/
pull.rs

1use thor_core::{find_repo, list_worktrees};
2use std::process::Command;
3
4/// Status of a pull operation on one worktree.
5pub enum PullStatus {
6    Ok,
7    Failed(String),
8    Skipped,
9}
10
11/// Result of pulling one worktree.
12pub struct PullResult {
13    pub branch: String,
14    pub status: PullStatus,
15}
16
17/// Pull --rebase in one or all worktrees.
18pub async fn pull(all: bool) -> anyhow::Result<Vec<PullResult>> {
19    if !all {
20        // Pull in current directory only
21        let output = Command::new("git")
22            .args(["pull", "--rebase"])
23            .output()?;
24
25        let branch = Command::new("git")
26            .args(["branch", "--show-current"])
27            .output()
28            .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
29            .unwrap_or_else(|_| "unknown".to_string());
30
31        let status = if output.status.success() {
32            PullStatus::Ok
33        } else {
34            PullStatus::Failed(String::from_utf8_lossy(&output.stderr).trim().to_string())
35        };
36
37        return Ok(vec![PullResult { branch, status }]);
38    }
39
40    // Pull all worktrees
41    let repo = find_repo()?;
42    let worktrees = list_worktrees(&repo).await?;
43    let mut results = Vec::new();
44
45    for wt in &worktrees {
46        let branch = wt.display_name();
47
48        // Check if has upstream by trying to resolve @{u}
49        let has_upstream = Command::new("git")
50            .args(["rev-parse", "--abbrev-ref", "@{u}"])
51            .current_dir(&wt.path)
52            .output()
53            .map(|o| o.status.success())
54            .unwrap_or(false);
55
56        if !has_upstream {
57            results.push(PullResult { branch, status: PullStatus::Skipped });
58            continue;
59        }
60
61        let output = Command::new("git")
62            .args(["pull", "--rebase"])
63            .current_dir(&wt.path)
64            .output()?;
65
66        let status = if output.status.success() {
67            PullStatus::Ok
68        } else {
69            PullStatus::Failed(String::from_utf8_lossy(&output.stderr).trim().to_string())
70        };
71
72        results.push(PullResult { branch, status });
73    }
74
75    Ok(results)
76}