In short: jj walks the view's bookmarks by name, keeps those whose name matches or whose local target is in
-r, groups each local bookmark with its tracked remotes, drops remotes that agree with the local
target unless asked, sorts the groups, and renders every entry with templates.bookmark_list. Then
it prints hints about conflicts and deleted bookmarks. It writes nothing.
The command is cmd_bookmark_list. The help text: "List
bookmarks and their targets. By default, a tracked remote bookmark will be included only if its target is
different from the local target. An untracked remote bookmark won't be listed"
(source). It is registered as List(BookmarkListArgs) with the
visible alias l (source,
dispatch).
1. Command-line surface
| Flag | Meaning |
|---|---|
NAMES (positional) | "Show bookmarks whose local name matches", as glob patterns by default (source). |
-r, --revision REVSETS | "Show bookmarks whose local targets are in the given revisions" (alias --revisions). "-r deleted_bookmark will not work since deleted_bookmark wouldn't have a local target" (source). |
-a, --all-remotes | "Show all tracked and untracked remote bookmarks including the ones whose targets are synchronized with the local bookmarks" (alias --all) (source). |
--remote REMOTE | "Show all tracked and untracked remote bookmarks belonging to this remote"; repeatable, glob by default, conflicts with -a (source). |
-t, --tracked | "Show tracked remote bookmarks only. This omits local Git-tracking bookmarks by default"; conflicts with -a (source). |
-c, --conflicted | "Show conflicted bookmarks only"; conflicts with -a (source). |
-T, --template TEMPLATE | Render each entry with this template; all zero-argument methods of CommitRef are keywords (source). |
--sort SORT_KEY | Comma-delimited sort keys, the first most significant; a - suffix sorts descending (source). The keys are name, author-name, author-email, author-date, committer-name, committer-email and committer-date (source). |
The global flags are on the CLI page.
2. Configuration
| Setting | Default | Effect |
|---|---|---|
templates.bookmark_list | format_commit_ref(self, "bookmark") ++ "\n" | Each entry, labelled bookmark_list (default, source). The alias is described under what is printed. |
ui.bookmark-list-sort-keys | ["name"] | The sort keys when --sort is not given; it must be an array of key strings (default, source, parser). |
ui.pager | The command requests the pager (source). |
3. End-to-end flow
4. Core architecture touchpoints
| Piece | Role here |
|---|---|
View::bookmarks | "Iterates pair of local and remote bookmarks by bookmark name": each name with its local target and its remote refs. See the view. |
RefFilterPredicates | The name and remote matchers, the matched local targets, and the three switches for local-only, synced and untracked refs. |
collect_items | Builds RefListItems: a primary ref, local or untracked remote, and the remote refs it tracks. Shared with jj tag list. |
sort | Stable multi-key sort; loads commits only when a key needs them. |
CommitRef | The template type, made by local, remote or remote_only; its keywords (name, remote, present, conflict, tracked, tracking_ahead_count, synced, …) are in builtin_commit_ref_methods. |
default_ignored_remote_name | The git pseudo-remote on the Git backend, none otherwise; --tracked leaves it out (source). See jj git import. |
5. What it reads, and snapshotting
It goes through workspace_helper, so the working copy is snapshotted first unless
--ignore-working-copy is given (source). It then reads only
the view's bookmarks and the commits the template prints, plus, for -r, the revset evaluation, and
for commit-based sort keys, each group's first target commit (source). It
starts no transaction and writes no operation.
6. Algorithm and invariants
Which bookmarks are listed
Names and revisions are OR-ed, "like cmd_git_push()": with only -r the name pattern
matches nothing, with neither it matches everything (source). The revsets
are intersected with bookmarks(all()) "to minimize the lookup space" and evaluated to commit ids;
a bookmark is kept if its name matches or any of its local targets is one of them. -c then keeps
only bookmarks whose local target is conflicted (source).
Grouping local and remote
For each kept name, the remote refs whose remote matches are split into tracked and untracked. A tracked ref
whose target equals the local target is dropped unless -t, -a or
--remote is given. A group, the local ref followed by the remaining tracked refs, is emitted if the
local bookmark is present and local-only refs are wanted, or if any tracked ref remains, which is how a deleted
local bookmark still shows with its remote. With -a or --remote, each untracked remote
ref is its own group, printed as name@remote (source).
| Flags | Local-only | Synced tracked | Untracked |
|---|---|---|---|
| none | yes | no | no |
-a | yes | yes | yes |
--remote R | no | yes | yes |
-t | no | yes | no |
The three switches are set at list.rs.
Sorting
The view yields names in order, so the input is already sorted by name; the sort runs the keys from least to
most significant with stable sorts, skipping trailing name keys
(source). name compares the name, then the remote. The
commit keys use the group's first present target; a group without one sorts as missing, which comes before any commit in ascending order
(source). Tracked remote refs always stay under their local bookmark.
What is printed
The default template calls format_commit_ref (source). A local
bookmark prints name: and its commit summary, or (deleted) when absent. A tracked
remote prints indented as @remote, with "(ahead by N commits, behind by N commits)" against the
local target, or "(not created yet)" when the remote ref is absent
(source). An untracked remote prints name@remote: . A conflicted
target prints (conflicted): and one line per removed (-) and added (+)
commit, and a term with no commit prints (absent) (source).
7. Errors and edge cases
| Situation | Behaviour |
|---|---|
| An exact name that matches no local or remote bookmark | "Warning: No matching bookmarks for names: …"; glob patterns never warn (source). |
| A listed local bookmark is conflicted | "Hint: Some bookmarks have conflicts. Use jj bookmark set <name> -r <rev> to resolve." (source, test). See jj bookmark set. |
| A listed bookmark is deleted locally but tracked on a real remote | "Hint: Bookmarks marked as deleted can be *deleted permanently* on the remote by running jj git push --deleted. Use jj bookmark forget if you don't want that." (source). See jj git push and jj bookmark forget. |
Deleted, tracked only by the git pseudo-remote | "Hint: Bookmarks marked as deleted will be deleted from the underlying Git repo on the next jj git export." Only one of the two hints is printed, and neither off the Git backend (source). |
An unknown --sort key | Rejected by clap with the list of possible values, exit status 2 (test). |
ui.bookmark-list-sort-keys not an array of keys | A config error: "Expected an array of sort keys as strings" or "Expected sort key as a string" (source). |
-a with --remote, -t or -c | Rejected by clap (source). |
-r naming a deleted bookmark | It has no local target, so it cannot be found that way; list it by name instead (source). |
8. Example output
After deleting, tracking, untracking and moving bookmarks against a clone, upstream's test shows the default listing (source):
$ jj bookmark list
absent-tracked: wqnwkozp 0353dd35 (empty) local-only
@origin (not created yet)
local-only: wqnwkozp 0353dd35 (empty) local-only
remote-delete (deleted)
@origin: vruxwmqv b32031cf (empty) remote-delete
remote-sync: rlvkpnrz 7a07dbee (empty) remote-sync
remote-unsync: wqnwkozp 0353dd35 (empty) local-only
@origin (ahead by 1 commits, behind by 1 commits): zsuskuln 553203ba (empty) remote-unsync
Hint: Bookmarks marked as deleted can be *deleted permanently* on the remote by running `jj git push --deleted`. Use `jj bookmark forget` if you don't want that.
--all-remotes adds the synced remote-sync@origin under its local bookmark and the
untracked remote-untrack@origin as its own entry (source):
$ jj bookmark list --all-remotes
…
remote-sync: rlvkpnrz 7a07dbee (empty) remote-sync
@origin: rlvkpnrz 7a07dbee (empty) remote-sync
remote-unsync: wqnwkozp 0353dd35 (empty) local-only
@origin (ahead by 1 commits, behind by 1 commits): zsuskuln 553203ba (empty) remote-unsync
remote-untrack@origin: royxmykx 149bc756 (empty) remote-untrack
A custom template sorted by two keys (source):
$ jj bookmark list -T 'name ++ ": " ++ if(normal_target, normal_target.committer().email()) ++ "\n"' \
--sort committer-email,committer-date-
b: alice@g.c
a: bob@g.c
c: bob@g.c
See also jj bookmark track and the view.