diff --git a/CHANGELOG.md b/CHANGELOG.md index 08308232b..8f82bc554 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### New features +* `jj git push --deleted` will remove all locally deleted branches from the remote. + ### Fixed bugs * Modify/delete conflicts now include context lines diff --git a/src/commands/git.rs b/src/commands/git.rs index 2f7419b41..e2898fae1 100644 --- a/src/commands/git.rs +++ b/src/commands/git.rs @@ -111,7 +111,7 @@ pub struct GitCloneArgs { /// all branches. Use `--change` to generate branch names based on the change /// IDs of specific commits. #[derive(clap::Args, Clone, Debug)] -#[command(group(ArgGroup::new("what").args(&["branch", "all", "change"])))] +#[command(group(ArgGroup::new("what").args(&["branch", "all", "change", "deleted"])))] pub struct GitPushArgs { /// The remote to push to (only named remotes are supported) #[arg(long)] @@ -122,6 +122,9 @@ pub struct GitPushArgs { /// Push all branches #[arg(long)] all: bool, + /// Push all deleted branches + #[arg(long)] + deleted: bool, /// Push this commit by creating a branch based on its change ID (can be /// repeated) #[arg(long)] @@ -524,7 +527,7 @@ fn cmd_git_push( let mut tx; let mut branch_updates = vec![]; let mut seen_branches = hashset! {}; - if args.all { + if args.all || args.deleted { // TODO: Is it useful to warn about conflicted branches? for (branch_name, branch_target) in workspace_command.repo().view().branches() { if !seen_branches.insert(branch_name.clone()) { @@ -536,12 +539,17 @@ fn cmd_git_push( BranchPushAction::LocalConflicted => {} BranchPushAction::RemoteConflicted => {} BranchPushAction::Update(update) => { - branch_updates.push((branch_name.clone(), update)); + if args.all || branch_target.local_target.is_none() { + branch_updates.push((branch_name.clone(), update)); + } } } } - tx = workspace_command - .start_transaction(&format!("push all branches to git remote {}", &remote)); + tx = workspace_command.start_transaction(&format!( + "push all {}branches to git remote {}", + if args.deleted { "deleted " } else { "" }, + &remote + )); } else if !args.branch.is_empty() { for branch_name in &args.branch { if !seen_branches.insert(branch_name.clone()) { diff --git a/tests/test_git_push.rs b/tests/test_git_push.rs index 944105499..e66b76e86 100644 --- a/tests/test_git_push.rs +++ b/tests/test_git_push.rs @@ -369,3 +369,20 @@ fn test_git_push_missing_committer() { Error: Won't push commit f73024ee65ec since it has no description and it has no author and/or committer set "###); } + +#[test] +fn test_git_push_deleted() { + let (test_env, workspace_root) = set_up(); + + test_env.jj_cmd_success(&workspace_root, &["branch", "delete", "branch1"]); + let stdout = test_env.jj_cmd_success(&workspace_root, &["git", "push", "--deleted"]); + insta::assert_snapshot!(stdout, @r###" + Branch changes to push to origin: + Delete branch branch1 from 45a3aa29e907 + "###); + let stdout = + test_env.jj_cmd_success(&workspace_root, &["git", "push", "--deleted", "--dry-run"]); + insta::assert_snapshot!(stdout, @r###" + Nothing changed. + "###); +}