From a21397bfff7d5f5633e8ecb6f5fd2b647ecc69ac Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Fri, 7 Jul 2023 22:03:36 +0900 Subject: [PATCH] git: move remove/rename remote logic to library These functions are somewhat similar to git::import/export_refs() in that git_refs and branches are manipulated. --- lib/src/git.rs | 58 +++++++++++++++++++++++++++++++++++++++ src/commands/git.rs | 66 +++++++++------------------------------------ 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/lib/src/git.rs b/lib/src/git.rs index 0f7252a59..6eecd7704 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -479,6 +479,64 @@ pub fn export_some_refs( Ok(failed_branches) } +pub fn remove_remote( + mut_repo: &mut MutableRepo, + git_repo: &git2::Repository, + remote_name: &str, +) -> Result<(), git2::Error> { + git_repo.remote_delete(remote_name)?; + let mut branches_to_delete = vec![]; + for (branch, target) in mut_repo.view().branches() { + if target.remote_targets.contains_key(remote_name) { + branches_to_delete.push(branch.clone()); + } + } + let prefix = format!("refs/remotes/{remote_name}/"); + let git_refs_to_delete = mut_repo + .view() + .git_refs() + .keys() + .filter_map(|r| r.starts_with(&prefix).then(|| r.clone())) + .collect_vec(); + for branch in branches_to_delete { + mut_repo.remove_remote_branch(&branch, remote_name); + } + for git_ref in git_refs_to_delete { + mut_repo.remove_git_ref(&git_ref); + } + Ok(()) +} + +pub fn rename_remote( + mut_repo: &mut MutableRepo, + git_repo: &git2::Repository, + old_remote_name: &str, + new_remote_name: &str, +) -> Result<(), git2::Error> { + git_repo.remote_rename(old_remote_name, new_remote_name)?; + mut_repo.rename_remote(old_remote_name, new_remote_name); + let prefix = format!("refs/remotes/{old_remote_name}/"); + let git_refs = mut_repo + .view() + .git_refs() + .iter() + .filter_map(|(r, target)| { + r.strip_prefix(&prefix).map(|p| { + ( + r.clone(), + format!("refs/remotes/{new_remote_name}/{p}"), + target.clone(), + ) + }) + }) + .collect_vec(); + for (old, new, target) in git_refs { + mut_repo.remove_git_ref(&old); + mut_repo.set_git_ref(new, target); + } + Ok(()) +} + #[derive(Error, Debug, PartialEq)] pub enum GitFetchError { #[error("No git remote named '{0}'")] diff --git a/src/commands/git.rs b/src/commands/git.rs index a01c0de4f..22fe5f74f 100644 --- a/src/commands/git.rs +++ b/src/commands/git.rs @@ -229,34 +229,15 @@ fn cmd_git_remote_remove( if git_repo.find_remote(&args.remote).is_err() { return Err(user_error("Remote doesn't exist")); } - git_repo - .remote_delete(&args.remote) + let mut tx = + workspace_command.start_transaction(&format!("remove git remote {}", &args.remote)); + git::remove_remote(tx.mut_repo(), &git_repo, &args.remote) .map_err(|err| user_error(err.to_string()))?; - let mut branches_to_delete = vec![]; - for (branch, target) in repo.view().branches() { - if target.remote_targets.contains_key(&args.remote) { - branches_to_delete.push(branch.clone()); - } + if tx.mut_repo().has_changes() { + tx.finish(ui) + } else { + Ok(()) // Do not print "Nothing changed." } - let prefix = format!("refs/remotes/{}/", args.remote); - let git_refs_to_delete = repo - .view() - .git_refs() - .keys() - .filter_map(|r| r.starts_with(&prefix).then(|| r.clone())) - .collect_vec(); - if !branches_to_delete.is_empty() || !git_refs_to_delete.is_empty() { - let mut tx = - workspace_command.start_transaction(&format!("remove git remote {}", &args.remote)); - for branch in branches_to_delete { - tx.mut_repo().remove_remote_branch(&branch, &args.remote); - } - for git_ref in git_refs_to_delete { - tx.mut_repo().remove_git_ref(&git_ref); - } - tx.finish(ui)?; - } - Ok(()) } fn cmd_git_remote_rename( @@ -270,38 +251,15 @@ fn cmd_git_remote_rename( if git_repo.find_remote(&args.old).is_err() { return Err(user_error("Remote doesn't exist")); } - git_repo - .remote_rename(&args.old, &args.new) - .map_err(|err| user_error(err.to_string()))?; let mut tx = workspace_command .start_transaction(&format!("rename git remote {} to {}", &args.old, &args.new)); - tx.mut_repo().rename_remote(&args.old, &args.new); - - let prefix = format!("refs/remotes/{}/", args.old); - let git_refs = tx - .mut_repo() - .view() - .git_refs() - .iter() - .filter_map(|(r, target)| { - r.strip_prefix(&prefix).map(|p| { - ( - r.clone(), - format!("refs/remotes/{}/{p}", args.new), - target.clone(), - ) - }) - }) - .collect_vec(); - for (old, new, target) in git_refs { - tx.mut_repo().remove_git_ref(&old); - tx.mut_repo().set_git_ref(new, target); - } - + git::rename_remote(tx.mut_repo(), &git_repo, &args.old, &args.new) + .map_err(|err| user_error(err.to_string()))?; if tx.mut_repo().has_changes() { - tx.finish(ui)?; + tx.finish(ui) + } else { + Ok(()) // Do not print "Nothing changed." } - Ok(()) } fn cmd_git_remote_list(