// Copyright 2020-2023 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.use clap_complete::ArgValueCandidates;use jj_lib::op_store::RefTarget;use jj_lib::ref_name::RefNameBuf;use crate::cli_util::CommandHelper;use crate::cli_util::has_tracked_remote_bookmarks;use crate::command_error::CommandError;use crate::command_error::user_error;use crate::complete;use crate::revset_util;use crate::ui::Ui;/// Rename `old` bookmark name to `new` bookmark name////// The new bookmark name points at the same commit as the old bookmark name.#[derive(clap::Args, Clone, Debug)]pub struct BookmarkRenameArgs { /// The old name of the bookmark #[arg( value_parser = revset_util::parse_bookmark_name, add = ArgValueCandidates::new(complete::local_bookmarks), )] old: RefNameBuf, /// The new name of the bookmark #[arg(value_parser = revset_util::parse_bookmark_name)] new: RefNameBuf,}pub fn cmd_bookmark_rename( ui: &mut Ui, command: &CommandHelper, args: &BookmarkRenameArgs,) -> Result<(), CommandError> { let mut workspace_command = command.workspace_helper(ui)?; let view = workspace_command.repo().view(); let old_bookmark = &args.old; let ref_target = view.get_local_bookmark(old_bookmark).clone(); if ref_target.is_absent() { return Err(user_error(format!( "No such bookmark: {old_bookmark}", old_bookmark = old_bookmark.as_symbol() ))); } let new_bookmark = &args.new; if view.get_local_bookmark(new_bookmark).is_present() { return Err(user_error(format!( "Bookmark already exists: {new_bookmark}", new_bookmark = new_bookmark.as_symbol() ))); } let mut tx = workspace_command.start_transaction(); tx.repo_mut() .set_local_bookmark_target(new_bookmark, ref_target); tx.repo_mut() .set_local_bookmark_target(old_bookmark, RefTarget::absent()); tx.finish( ui, format!( "rename bookmark {old_bookmark} to {new_bookmark}", old_bookmark = old_bookmark.as_symbol(), new_bookmark = new_bookmark.as_symbol() ), )?; let view = workspace_command.repo().view(); if has_tracked_remote_bookmarks(view, old_bookmark) { writeln!( ui.warning_default(), "Tracked remote bookmarks for bookmark {old_bookmark} were not renamed.", old_bookmark = old_bookmark.as_symbol(), )?; writeln!( ui.hint_default(), "To rename the bookmark on the remote, you can `jj git push --bookmark \ {old_bookmark}` first (to delete it on the remote), and then `jj git push --bookmark \ {new_bookmark}`. `jj git push --all --deleted` would also be sufficient.", old_bookmark = old_bookmark.as_symbol(), new_bookmark = new_bookmark.as_symbol() )?; } if has_tracked_remote_bookmarks(view, new_bookmark) { // This isn't an error because bookmark renaming can't be propagated to // the remote immediately. "rename old new && rename new old" should be // allowed even if the original old bookmark had tracked remotes. writeln!( ui.warning_default(), "Tracked remote bookmarks for bookmark {new_bookmark} exist.", new_bookmark = new_bookmark.as_symbol() )?; writeln!( ui.hint_default(), "Run `jj bookmark untrack 'glob:{new_bookmark}@*'` to disassociate them.", // TODO: use .as_symbol() if pattern parser is ported to revset new_bookmark = new_bookmark.as_str() )?; } Ok(())}
// Copyright 2020-2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use clap_complete::ArgValueCandidates;
use jj_lib::op_store::RefTarget;
use jj_lib::ref_name::RefNameBuf;
use crate::cli_util::CommandHelper;
use crate::cli_util::has_tracked_remote_bookmarks;
use crate::command_error::CommandError;
use crate::command_error::user_error;
use crate::complete;
use crate::revset_util;
use crate::ui::Ui;
/// Rename `old` bookmark name to `new` bookmark name
///
/// The new bookmark name points at the same commit as the old bookmark name.
#[derive(clap::Args, Clone, Debug)]
pub struct BookmarkRenameArgs {
/// The old name of the bookmark
#[arg(
value_parser = revset_util::parse_bookmark_name,
add = ArgValueCandidates::new(complete::local_bookmarks),
)]
old: RefNameBuf,
/// The new name of the bookmark
#[arg(value_parser = revset_util::parse_bookmark_name)]
new: RefNameBuf,
}
pub fn cmd_bookmark_rename(
ui: &mut Ui,
command: &CommandHelper,
args: &BookmarkRenameArgs,
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let view = workspace_command.repo().view();
let old_bookmark = &args.old;
let ref_target = view.get_local_bookmark(old_bookmark).clone();
if ref_target.is_absent() {
return Err(user_error(format!(
"No such bookmark: {old_bookmark}",
old_bookmark = old_bookmark.as_symbol()
)));
}
let new_bookmark = &args.new;
if view.get_local_bookmark(new_bookmark).is_present() {
return Err(user_error(format!(
"Bookmark already exists: {new_bookmark}",
new_bookmark = new_bookmark.as_symbol()
)));
}
let mut tx = workspace_command.start_transaction();
tx.repo_mut()
.set_local_bookmark_target(new_bookmark, ref_target);
tx.repo_mut()
.set_local_bookmark_target(old_bookmark, RefTarget::absent());
tx.finish(
ui,
format!(
"rename bookmark {old_bookmark} to {new_bookmark}",
old_bookmark = old_bookmark.as_symbol(),
new_bookmark = new_bookmark.as_symbol()
),
)?;
let view = workspace_command.repo().view();
if has_tracked_remote_bookmarks(view, old_bookmark) {
writeln!(
ui.warning_default(),
"Tracked remote bookmarks for bookmark {old_bookmark} were not renamed.",
old_bookmark = old_bookmark.as_symbol(),
)?;
writeln!(
ui.hint_default(),
"To rename the bookmark on the remote, you can `jj git push --bookmark \
{old_bookmark}` first (to delete it on the remote), and then `jj git push --bookmark \
{new_bookmark}`. `jj git push --all --deleted` would also be sufficient.",
old_bookmark = old_bookmark.as_symbol(),
new_bookmark = new_bookmark.as_symbol()
)?;
}
if has_tracked_remote_bookmarks(view, new_bookmark) {
// This isn't an error because bookmark renaming can't be propagated to
// the remote immediately. "rename old new && rename new old" should be
// allowed even if the original old bookmark had tracked remotes.
writeln!(
ui.warning_default(),
"Tracked remote bookmarks for bookmark {new_bookmark} exist.",
new_bookmark = new_bookmark.as_symbol()
)?;
writeln!(
ui.hint_default(),
"Run `jj bookmark untrack 'glob:{new_bookmark}@*'` to disassociate them.",
// TODO: use .as_symbol() if pattern parser is ported to revset
new_bookmark = new_bookmark.as_str()
)?;
}
Ok(())
}