Skip to main content

git_stk/commands/
rename.rs

1use anyhow::Result;
2use clap::ArgAction;
3use clap_complete::engine::ArgValueCompleter;
4
5use crate::commands::Run;
6use crate::completions;
7use crate::providers::{detect_provider, review_provider};
8use crate::style;
9use crate::{git, stack};
10
11/// Rename a branch and retarget its stack children.
12#[derive(Debug, clap::Args)]
13pub struct Rename {
14    /// New name for the current branch, or a branch and its new name.
15    #[arg(
16        required = true,
17        num_args = 1..=2,
18        value_name = "[BRANCH] NEW_NAME",
19        add = ArgValueCompleter::new(completions::branch_candidates),
20    )]
21    names: Vec<String>,
22    /// Print the rename and retargets without changing anything.
23    #[arg(long, action = ArgAction::SetTrue)]
24    dry_run: bool,
25}
26
27impl Run for Rename {
28    fn run(self) -> Result<()> {
29        let (old, new) = match self.names.as_slice() {
30            [new] => (git::current_branch()?, new.clone()),
31            [old, new] => (old.clone(), new.clone()),
32            _ => unreachable!("clap enforces one or two names"),
33        };
34        rename(&old, &new, self.dry_run)
35    }
36}
37
38fn rename(old: &str, new: &str, dry_run: bool) -> Result<()> {
39    stack::rename_branch(old, new, dry_run)?;
40
41    // Best effort: an existing review still heads the old branch name, and
42    // the platform does not follow local renames. Mark the rename so the next
43    // submit opens a fresh review for `new` and closes the stale one.
44    if let Ok(provider) = detect_provider() {
45        let review_provider = review_provider(provider.kind);
46        if let Ok(Some(review)) = review_provider.review_for_branch(old)
47            && review.branch == *old
48        {
49            if !dry_run {
50                stack::set_renamed_from(new, old)?;
51            }
52            anstream::println!(
53                "{} review {} still heads {old}; your next submit opens a fresh \
54                 review for {new} and closes {}",
55                style::paint(style::WARN, "warning:"),
56                review.id,
57                review.id
58            );
59        }
60    }
61
62    Ok(())
63}