diff --git a/config.toml b/config.toml index 55568fe..f93447e 100644 --- a/config.toml +++ b/config.toml @@ -94,6 +94,9 @@ commands = [ # `git prole add -b ...` will create a directory named `some-ticket-title`. # (The branch name will still be unchanged and way too long.) # +# Note that if the result of applying your regex substitutions includes a `/`, +# the last component of the result will be used. +# # For completeness, you can also specify how many replacements are performed: # # [[add.branch_replacements]] diff --git a/src/add.rs b/src/add.rs index 211f73b..a68aba2 100644 --- a/src/add.rs +++ b/src/add.rs @@ -119,7 +119,6 @@ impl<'a> WorktreePlan<'a> { }; self.git.worktree().add_command( - // TODO: What if the destination already exists? &self.destination, &AddWorktreeOpts { force_branch, @@ -170,6 +169,14 @@ impl<'a> WorktreePlan<'a> { pub fn execute(&self) -> miette::Result<()> { let mut command = self.command(); + // Test: `add_destination_exists` + if self.destination.exists() { + return Err(miette!( + "Worktree destination {} already exists", + self.destination.display_path_cwd() + )); + } + tracing::info!("{self}"); tracing::debug!("{self:#?}"); @@ -179,10 +186,11 @@ impl<'a> WorktreePlan<'a> { '$'.if_supports_color(Stream::Stdout, |text| text.green()), Utf8ProgramAndArgs::from(&command) ); - } else { - command.status_checked()?; - self.copy_untracked()?; + return Ok(()); } + + command.status_checked()?; + self.copy_untracked()?; self.run_commands()?; Ok(()) } diff --git a/src/git/worktree/mod.rs b/src/git/worktree/mod.rs index e437075..7c257fe 100644 --- a/src/git/worktree/mod.rs +++ b/src/git/worktree/mod.rs @@ -272,7 +272,20 @@ where } .into_owned(); } - dirname.into() + + if dirname.contains(std::path::MAIN_SEPARATOR_STR) { + let final_component = final_component(&dirname); + tracing::warn!( + %branch, + after_replacements=%dirname, + using=%final_component, + "Applying `add.branch_replacements` substitutions resulted in a directory name which includes a `{}`", + std::path::MAIN_SEPARATOR_STR, + ); + final_component.to_owned().into() + } else { + dirname.into() + } } } diff --git a/tests/add_destination_exists.rs b/tests/add_destination_exists.rs new file mode 100644 index 0000000..b37ff1d --- /dev/null +++ b/tests/add_destination_exists.rs @@ -0,0 +1,21 @@ +use command_error::CommandExt; +use test_harness::GitProle; + +#[test] +fn add_destination_exists() -> miette::Result<()> { + let prole = GitProle::new().unwrap(); + prole.setup_worktree_repo("my-repo").unwrap(); + + prole.sh(r#" + cd my-repo || exit + mkdir puppy + "#)?; + + prole + .cd_cmd("my-repo/main") + .args(["add", "puppy"]) + .status_checked() + .unwrap_err(); + + Ok(()) +} diff --git a/tests/config_add_branch_replacements_path_separator.rs b/tests/config_add_branch_replacements_path_separator.rs new file mode 100644 index 0000000..68bec69 --- /dev/null +++ b/tests/config_add_branch_replacements_path_separator.rs @@ -0,0 +1,36 @@ +use command_error::CommandExt; +use test_harness::GitProle; +use test_harness::WorktreeState; + +#[test] +fn config_add_branch_replacements_path_separator() -> miette::Result<()> { + let prole = GitProle::new()?; + prole.setup_worktree_repo("my-repo")?; + prole.write_config( + r#" + [[add.branch_replacements]] + find = "doggy" + replace = "silly" + "#, + )?; + + prole + .cd_cmd("my-repo/main") + .args(["add", "-b", "puppy/doggy"]) + .status_checked() + .unwrap(); + + prole + .repo_state("my-repo") + .worktrees([ + WorktreeState::new_bare(), + WorktreeState::new("main").branch("main"), + // Last component of the result of the replacements is used: + WorktreeState::new("silly") + .branch("puppy/doggy") + .upstream("main"), + ]) + .assert(); + + Ok(()) +}