diff --git a/CHANGELOG.md b/CHANGELOG.md index fec9be3750..aa19935e91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). * New template functions `pad_start()`, `pad_end()`, `truncate_start()`, and `truncate_end()` are added. +* `jj bookmark list` gained a `--remote REMOTE` option to display bookmarks + belonging to a remote. This option can be combined with `--tracked` or + `--conflicted`. + ### Fixed bugs * Error on `trunk()` revset resolution is now handled gracefully. diff --git a/cli/src/commands/bookmark/list.rs b/cli/src/commands/bookmark/list.rs index 085acf2082..748e368b63 100644 --- a/cli/src/commands/bookmark/list.rs +++ b/cli/src/commands/bookmark/list.rs @@ -43,6 +43,12 @@ pub struct BookmarkListArgs { #[arg(long, short, alias = "all")] all_remotes: bool, + /// Show all tracking and non-tracking remote bookmarks belonging + /// to this remote. Can be combined with `--tracked` or + /// `--conflicted` to filter the bookmarks shown (can be repeated) + #[arg(long = "remote", value_name = "REMOTE", conflicts_with_all = ["all_remotes"])] + remotes: Vec, + /// Show remote tracked bookmarks only. Omits local Git-tracking bookmarks /// by default #[arg(long, short, conflicts_with_all = ["all_remotes"])] @@ -141,15 +147,22 @@ pub fn cmd_bookmark_list( for (name, bookmark_target) in bookmarks_to_list { let local_target = bookmark_target.local_target; let remote_refs = bookmark_target.remote_refs; - let (mut tracking_remote_refs, untracked_remote_refs) = remote_refs + let (mut tracking_remote_refs, mut untracked_remote_refs) = remote_refs .iter() .copied() .partition::, _>(|&(_, remote_ref)| remote_ref.is_tracking()); + if !args.remotes.is_empty() { + let filter = |refs: &mut Vec<_>| { + refs.retain(|&(remote_name, _)| args.remotes.iter().any(|r| r == remote_name)); + }; + filter(&mut tracking_remote_refs); + filter(&mut untracked_remote_refs); + } if args.tracked { tracking_remote_refs .retain(|&(remote, _)| remote != git::REMOTE_NAME_FOR_LOCAL_GIT_REPO); - } else if !args.all_remotes { + } else if !args.all_remotes && args.remotes.is_empty() { tracking_remote_refs.retain(|&(_, remote_ref)| remote_ref.target != *local_target); } @@ -174,7 +187,7 @@ pub fn cmd_bookmark_list( .any(|&(remote, _)| remote != git::REMOTE_NAME_FOR_LOCAL_GIT_REPO); } - if args.all_remotes { + if args.all_remotes || !args.remotes.is_empty() { for &(remote, remote_ref) in &untracked_remote_refs { let ref_name = RefName::remote_only(name, remote, remote_ref.target.clone()); template.format(&ref_name, formatter.as_mut())?; diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index 4b629ae093..9a2e067e67 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -318,6 +318,7 @@ For information about bookmarks, see https://martinvonz.github.io/jj/latest/book ###### **Options:** * `-a`, `--all-remotes` — Show all tracking and non-tracking remote bookmarks including the ones whose targets are synchronized with the local bookmarks +* `--remote ` — Show all tracking and non-tracking remote bookmarks belonging to this remote. Can be combined with `--tracked` or `--conflicted` to filter the bookmarks shown (can be repeated) * `-t`, `--tracked` — Show remote tracked bookmarks only. Omits local Git-tracking bookmarks by default * `-c`, `--conflicted` — Show conflicted bookmarks only * `-r`, `--revisions ` — Show bookmarks whose local targets are in the given revisions diff --git a/cli/tests/test_bookmark_command.rs b/cli/tests/test_bookmark_command.rs index 94f1d5c22d..c0b751ae69 100644 --- a/cli/tests/test_bookmark_command.rs +++ b/cli/tests/test_bookmark_command.rs @@ -1533,6 +1533,47 @@ fn test_bookmark_list_filtered() { "###); insta::assert_snapshot!(stderr, @""); + // Select bookmarks with --remote + let (stdout, stderr) = query(&["--remote", "origin"]); + insta::assert_snapshot!(stdout, @r#" + local-keep: kpqxywon c7b4c09c (empty) local-keep + remote-delete (deleted) + @origin: yxusvupt dad5f298 (empty) remote-delete + remote-keep: nlwprzpn 911e9120 (empty) remote-keep + @origin: nlwprzpn 911e9120 (empty) remote-keep + remote-rewrite: xyxluytn e31634b6 (empty) rewritten + @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite + "#); + insta::assert_snapshot!(stderr, @r#" + Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. + "#); + let (stdout, stderr) = query(&["--remote", "git"]); + insta::assert_snapshot!(stdout, @r#" + local-keep: kpqxywon c7b4c09c (empty) local-keep + @git: kpqxywon c7b4c09c (empty) local-keep + remote-keep: nlwprzpn 911e9120 (empty) remote-keep + @git: nlwprzpn 911e9120 (empty) remote-keep + remote-rewrite: xyxluytn e31634b6 (empty) rewritten + @git: xyxluytn e31634b6 (empty) rewritten + "#); + insta::assert_snapshot!(stderr, @""); + let (stdout, stderr) = query(&["--remote", "origin", "--remote", "git"]); + insta::assert_snapshot!(stdout, @r#" + local-keep: kpqxywon c7b4c09c (empty) local-keep + @git: kpqxywon c7b4c09c (empty) local-keep + remote-delete (deleted) + @origin: yxusvupt dad5f298 (empty) remote-delete + remote-keep: nlwprzpn 911e9120 (empty) remote-keep + @git: nlwprzpn 911e9120 (empty) remote-keep + @origin: nlwprzpn 911e9120 (empty) remote-keep + remote-rewrite: xyxluytn e31634b6 (empty) rewritten + @git: xyxluytn e31634b6 (empty) rewritten + @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite + "#); + insta::assert_snapshot!(stderr, @r#" + Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. + "#); + // Can select deleted bookmark by name pattern, but not by revset. let (stdout, stderr) = query(&["remote-delete"]); insta::assert_snapshot!(stdout, @r###" @@ -1578,6 +1619,21 @@ fn test_bookmark_list_filtered() { @origin (ahead by 1 commits, behind by 1 commits): xyxluytn hidden 3e9a5af6 (empty) remote-rewrite "###); insta::assert_snapshot!(stderr, @""); + + // … but still filtered by --remote + let (stdout, stderr) = query(&[ + "local-keep", + "-rbookmarks(remote-rewrite)", + "--remote", + "git", + ]); + insta::assert_snapshot!(stdout, @r#" + local-keep: kpqxywon c7b4c09c (empty) local-keep + @git: kpqxywon c7b4c09c (empty) local-keep + remote-rewrite: xyxluytn e31634b6 (empty) rewritten + @git: xyxluytn e31634b6 (empty) rewritten + "#); + insta::assert_snapshot!(stderr, @""); } #[test] @@ -1752,6 +1808,24 @@ fn test_bookmark_list_tracked() { Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. "###); + let (stdout, stderr) = test_env.jj_cmd_ok( + &local_path, + &["bookmark", "list", "--tracked", "--remote", "origin"], + ); + insta::assert_snapshot!(stdout, @r#" + remote-delete (deleted) + @origin: mnmymoky 203e60eb (empty) remote-delete + remote-sync: zwtyzrop c761c7ea (empty) remote-sync + @origin: zwtyzrop c761c7ea (empty) remote-sync + remote-unsync: nmzmmopx e1da745b (empty) local-only + @origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync + remote-untrack@origin: vmortlor 71a16b05 (empty) remote-untrack + "# + ); + insta::assert_snapshot!(stderr, @r###" + Hint: Bookmarks marked as deleted will be *deleted permanently* on the remote on the next `jj git push`. Use `jj bookmark forget` to prevent this. + "###); + let (stdout, stderr) = test_env.jj_cmd_ok( &local_path, &["bookmark", "list", "--tracked", "remote-unsync"],