Skip to content

Commit

Permalink
cli: accept remote bookmark patterns in bookmark forget
Browse files Browse the repository at this point in the history
Being able to pass a specific remote bookmark to forget is a useful
feature to have, and it makes the `--include-remotes` flag be less of a
special case, since now it's basically sugar for explicitly passing all
of the remote bookmarks as arguments.
  • Loading branch information
scott2000 committed Feb 8, 2025
1 parent 9f759de commit 8c8dcdc
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
`ellipsis` parameter; passing this prepends or appends the ellipsis to the
content if it is truncated to fit the maximum width.

* `jj bookmark forget` can now also accept remote bookmarks as arguments. For
instance, `jj bookmark forget bookmark@remote` will forget the target of
`bookmark@remote` until the next `jj git fetch` from the remote.

### Fixed bugs

* `jj status` now shows untracked files under untracked directories.
Expand Down
42 changes: 38 additions & 4 deletions cli/src/commands/bookmark/forget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

use clap_complete::ArgValueCandidates;
use itertools::Either;
use itertools::Itertools as _;
use jj_lib::op_store::BookmarkTarget;
use jj_lib::op_store::RefTarget;
Expand All @@ -21,7 +22,9 @@ use jj_lib::str_util::StringPattern;
use jj_lib::view::View;

use super::find_bookmarks_with;
use super::find_remote_bookmarks;
use crate::cli_util::CommandHelper;
use crate::cli_util::LocalOrRemoteBookmarkNamePattern;
use crate::command_error::CommandError;
use crate::complete;
use crate::ui::Ui;
Expand All @@ -31,6 +34,18 @@ use crate::ui::Ui;
/// If a local bookmark is forgotten, any corresponding remote bookmarks will
/// become untracked. A forgotten bookmark will not impact remotes on future
/// pushes.
///
/// Remote bookmarks can also be forgotten using the normal `bookmark@remote`
/// syntax. If a remote bookmark is forgotten, it will be recreated on future
/// fetches if it still exists in the remote.
///
/// Git-tracking bookmarks (e.g. `bookmark@git`) can also be forgotten. If a
/// Git-tracking bookmark is forgotten, it will be deleted from the underlying
/// Git repo on the next `jj git export`. Otherwise, the bookmark will be
/// recreated on the next `jj git import` if it still exists in the underlying
/// Git repo. In colocated repos, `jj git export` is run automatically after
/// every command, so forgetting a Git-tracking bookmark has no effect in a
/// colocated repo.
#[derive(clap::Args, Clone, Debug)]
pub struct BookmarkForgetArgs {
/// When forgetting a local bookmark, also forget any corresponding remote
Expand All @@ -49,10 +64,9 @@ pub struct BookmarkForgetArgs {
/// https://jj-vcs.github.io/jj/latest/revsets/#string-patterns
#[arg(
required = true,
value_parser = StringPattern::parse,
add = ArgValueCandidates::new(complete::bookmark_names),
add = ArgValueCandidates::new(complete::local_and_remote_bookmarks),
)]
names: Vec<StringPattern>,
names: Vec<LocalOrRemoteBookmarkNamePattern>,
}

pub fn cmd_bookmark_forget(
Expand All @@ -62,17 +76,32 @@ pub fn cmd_bookmark_forget(
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let repo = workspace_command.repo().clone();
let matched_bookmarks = find_forgettable_bookmarks(repo.view(), &args.names)?;
let (local_bookmarks, remote_bookmarks): (Vec<_>, Vec<_>) =
args.names.iter().cloned().partition_map(|name| match name {
LocalOrRemoteBookmarkNamePattern::Local(local) => Either::Left(local),
LocalOrRemoteBookmarkNamePattern::Remote(remote) => Either::Right(remote),
});
let matched_bookmarks = find_forgettable_bookmarks(repo.view(), &local_bookmarks)?;
let matched_remote_bookmarks = find_remote_bookmarks(repo.view(), &remote_bookmarks)?;
let mut tx = workspace_command.start_transaction();
let mut forgotten: usize = 0;
let mut untracked: usize = 0;
for (name, _) in &matched_remote_bookmarks {
tx.repo_mut()
.set_remote_bookmark(&name.bookmark, &name.remote, RemoteRef::absent());
forgotten += 1;
}
for (name, bookmark_target) in &matched_bookmarks {
if bookmark_target.local_target.is_present() {
tx.repo_mut()
.set_local_bookmark_target(name, RefTarget::absent());
forgotten += 1;
}
for (remote_name, remote_target) in &bookmark_target.remote_refs {
// If the remote bookmark was already deleted explicitly, skip it
if tx.repo().get_remote_bookmark(name, remote_name).is_absent() {
continue;
}
// If `--include-remotes` is specified, we forget the corresponding remote
// bookmarks instead of untracking them
if args.include_remotes {
Expand Down Expand Up @@ -102,6 +131,11 @@ pub fn cmd_bookmark_forget(
let forgotten_bookmarks = matched_bookmarks
.iter()
.map(|(name, _)| name.to_string())
.chain(
matched_remote_bookmarks
.iter()
.map(|(name, _)| name.to_string()),
)
.join(", ");
tx.finish(ui, format!("forget bookmark {forgotten_bookmarks}"))?;
Ok(())
Expand Down
4 changes: 4 additions & 0 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ Forget a bookmark without marking it as a deletion to be pushed

If a local bookmark is forgotten, any corresponding remote bookmarks will become untracked. A forgotten bookmark will not impact remotes on future pushes.

Remote bookmarks can also be forgotten using the normal `bookmark@remote` syntax. If a remote bookmark is forgotten, it will be recreated on future fetches if it still exists in the remote.

Git-tracking bookmarks (e.g. `bookmark@git`) can also be forgotten. If a Git-tracking bookmark is forgotten, it will be deleted from the underlying Git repo on the next `jj git export`. Otherwise, the bookmark will be recreated on the next `jj git import` if it still exists in the underlying Git repo. In colocated repos, `jj git export` is run automatically after every command, so forgetting a Git-tracking bookmark has no effect in a colocated repo.

**Usage:** `jj bookmark forget [OPTIONS] <NAMES>...`

###### **Arguments:**
Expand Down
27 changes: 26 additions & 1 deletion cli/tests/test_bookmark_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,6 @@ fn test_bookmark_delete_glob() {
error: invalid value 'whatever:bookmark' for '<NAMES>...': Invalid string pattern kind `whatever:`
For more information, try '--help'.
Hint: Try prefixing with one of `exact:`, `glob:`, `regex:`, or `substring:`
");
}

Expand Down Expand Up @@ -833,6 +832,32 @@ fn test_bookmark_forget_fetched_bookmark() {
feature1: ooosovrs 38aefb17 (empty) another message
@origin: ooosovrs 38aefb17 (empty) another message
"###);

// TEST 4: Explicitly naming the remote bookmarks has the same behavior as
// --include-remotes (same as test 1)
test_env.jj_cmd_ok(
&repo_path,
&["bookmark", "forget", "feature1", "feature1@origin"],
);
insta::assert_snapshot!(get_bookmark_output(&test_env, &repo_path), @"");
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["git", "export"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @"");
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["git", "import"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Nothing changed.
"###);
insta::assert_snapshot!(get_bookmark_output(&test_env, &repo_path), @"");
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["git", "fetch", "--remote=origin"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
bookmark: feature1@origin [new] tracked
"###);
insta::assert_snapshot!(get_bookmark_output(&test_env, &repo_path), @r###"
feature1: ooosovrs 38aefb17 (empty) another message
@origin: ooosovrs 38aefb17 (empty) another message
"###);
}

#[test]
Expand Down
7 changes: 4 additions & 3 deletions cli/tests/test_completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,12 @@ fn test_bookmark_names() {
");

let stdout = test_env.jj_cmd_success(&repo_path, &["--", "jj", "bookmark", "forget", "a"]);
insta::assert_snapshot!(stdout, @r"
insta::assert_snapshot!(stdout, @r#"
aaa-local x
aaa-tracked x
aaa-untracked
");
aaa-tracked@origin
aaa-untracked@origin
"#);

let stdout = test_env.jj_cmd_success(
&repo_path,
Expand Down

0 comments on commit 8c8dcdc

Please sign in to comment.