Skip to content

Commit

Permalink
Implement a rename subcommand for the branch command.
Browse files Browse the repository at this point in the history
This is really a simple change that does the following in a transaction:
* Set the new branch name to point to the same commit as the old branch name.
* Set the old branch name to point to no commit (hence deleting the old name).

Before it starts, it confirms that the new branch name is not already in use.
  • Loading branch information
essiene committed Dec 13, 2023
1 parent 90e241c commit 2444394
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### New features

* Information about new and resolved conflicts is now printed by every command.
* `jj branch` has gained a new `rename` subcommand that allows changing a branch
name atomically. `jj branch help rename` for details.

### Fixed bugs

Expand Down
55 changes: 55 additions & 0 deletions cli/src/commands/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub enum BranchSubcommand {
Forget(BranchForgetArgs),
#[command(visible_alias("l"))]
List(BranchListArgs),
#[command(visible_alias("r"))]
Rename(BranchRenameArgs),
#[command(visible_alias("s"))]
Set(BranchSetArgs),
Track(BranchTrackArgs),
Expand Down Expand Up @@ -122,6 +124,22 @@ pub struct BranchForgetArgs {
pub glob: Vec<StringPattern>,
}

/// Rename an existing branch pointed to by a specified commit.
#[derive(clap::Args, Clone, Debug)]
pub struct BranchRenameArgs {
/// The old name of the branch.
#[arg(required = true)]
pub old: String,

/// The old branch's target revision.
#[arg(long, short)]
pub revision: Option<RevisionArg>,

/// The new name of the branch.
#[arg(required = true)]
pub new: String,
}

/// Update an existing branch to point to a certain commit.
#[derive(clap::Args, Clone, Debug)]
pub struct BranchSetArgs {
Expand Down Expand Up @@ -248,6 +266,7 @@ pub fn cmd_branch(
) -> Result<(), CommandError> {
match subcommand {
BranchSubcommand::Create(sub_args) => cmd_branch_create(ui, command, sub_args),
BranchSubcommand::Rename(sub_args) => cmd_branch_rename(ui, command, sub_args),
BranchSubcommand::Set(sub_args) => cmd_branch_set(ui, command, sub_args),
BranchSubcommand::Delete(sub_args) => cmd_branch_delete(ui, command, sub_args),
BranchSubcommand::Forget(sub_args) => cmd_branch_forget(ui, command, sub_args),
Expand Down Expand Up @@ -301,6 +320,42 @@ fn cmd_branch_create(
Ok(())
}

fn cmd_branch_rename(
ui: &mut Ui,
command: &CommandHelper,
args: &BranchRenameArgs,
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let target_commit =
workspace_command.resolve_single_rev(args.revision.as_deref().unwrap_or("@"), ui)?;
let repo = workspace_command.repo().as_ref();
let new_branch = &args.new;
let new_target = repo.view().get_local_branch(new_branch);
if !new_target.is_absent() {
return Err(user_error_with_hint(
format!("Branch name conflict: {new_branch}"),
"Target branch name already exists.",
));
}

let old_branch = &args.old;
let mut tx = workspace_command.start_transaction();
tx.mut_repo()
.set_local_branch_target(new_branch, RefTarget::normal(target_commit.id().clone()));
tx.mut_repo()
.set_local_branch_target(old_branch, RefTarget::absent());
tx.finish(
ui,
format!(
"rename {} to {}; still point to commit {}",
make_branch_term(&[old_branch]),
make_branch_term(&[new_branch]),
target_commit.id().hex()
),
)?;
Ok(())
}

fn cmd_branch_set(
ui: &mut Ui,
command: &CommandHelper,
Expand Down

0 comments on commit 2444394

Please sign in to comment.