Skip to main content

wip_git/commands/
load.rs

1use crate::git;
2use crate::ref_name;
3
4pub struct LoadResult {
5    pub name: String,
6    pub conflicts: bool,
7    pub popped: bool,
8    pub auto_stashed: bool,
9}
10
11pub fn run(
12    name: String,
13    pop: bool,
14    theirs: bool,
15    ours: bool,
16    remote: String,
17) -> Result<LoadResult, String> {
18    let user = ref_name::user()?;
19    let name = ref_name::resolve_name(Some(name))?;
20    let wip_ref = ref_name::wip_ref(&name, &user);
21
22    // Auto-stash if working tree is dirty
23    let status = git::git_stdout(&["status", "--porcelain"])?;
24    let auto_stashed = !status.is_empty();
25    if auto_stashed {
26        git::git(&[
27            "stash",
28            "push",
29            "--include-untracked",
30            "-m",
31            "wip-push autostash",
32        ])?;
33    }
34
35    // Fetch the WIP ref
36    git::git(&["fetch", &remote, &wip_ref])?;
37
38    // Cherry-pick --no-commit for 3-way merge
39    let mut cp_args = vec!["cherry-pick", "--no-commit", "FETCH_HEAD"];
40    if theirs {
41        cp_args.extend_from_slice(&["--strategy-option", "theirs"]);
42    } else if ours {
43        cp_args.extend_from_slice(&["--strategy-option", "ours"]);
44    }
45
46    let result = git::git_allow_fail(&cp_args)?;
47
48    let conflicts = result.stderr.contains("CONFLICT") || result.stdout.contains("CONFLICT");
49
50    if conflicts {
51        // leave index as-is so user can resolve
52    } else if result.stderr.contains("error") {
53        return Err(format!("cherry-pick failed: {}", result.stderr));
54    } else {
55        // Reset index so changes appear as unstaged (like stash pop)
56        git::git(&["reset", "HEAD"])?;
57    }
58
59    // Restore auto-stashed changes if no conflicts
60    if auto_stashed && !conflicts {
61        git::git_allow_fail(&["stash", "pop"])?;
62    }
63
64    // --pop: delete the remote ref after successful load
65    let popped = if pop {
66        let delete_refspec = format!(":{wip_ref}");
67        git::git(&["push", &remote, &delete_refspec])?;
68        true
69    } else {
70        false
71    };
72
73    Ok(LoadResult {
74        name,
75        conflicts,
76        popped,
77        auto_stashed,
78    })
79}