In short: jj matches the name patterns against local bookmarks, warns about exact names that don't
exist, and prints No bookmarks to delete. if nothing matched. Otherwise, in one
transaction, it sets each matched bookmark's local target to absent, prints
Deleted N bookmarks., and records delete bookmark <names>. A bookmark
with tracked remotes then shows as (deleted), and pushing propagates the deletion.
The command is cmd_bookmark_delete. Its help text
points to jj abandon for removing the
commits as well, and to jj bookmark forget
when the deletion shouldn't reach the remotes (source). How
pushes handle deleted bookmarks is on the git push
page; bookmark storage is on the view page.
1. Command-line surface
| Argument | Type | Default | Meaning |
|---|---|---|---|
NAMES (positional) | name patterns, required | — | Bookmarks to delete; globs by default, other string-pattern kinds allowed, several unioned (source, parse_union_name_patterns). |
2. Configuration
None of its own. Whether the deletion is later pushed depends on the bookmark being tracked on a
remote, which remotes.<name>.auto-track-bookmarks and jj bookmark track
control. In a colocated workspace, tx.finish exports the change to the Git repo, so the
Git branch is removed too.
3. End-to-end flow
4. Core architecture touchpoints
| Structure | Read / write | How | Explained on |
|---|---|---|---|
View.local_bookmarks | write | Each match is set to RefTarget::absent(), which removes the entry (source, set_local_bookmark_target). | view |
| Remote bookmarks | untouched | Tracked remote bookmarks keep their targets. A local name absent while a tracked remote exists is what jj shows as (deleted). | view |
| Commits, heads | untouched | Nothing is abandoned; the commits stay visible if anything else keeps them. | commits |
| Operation | write | One operation if anything matched. | operations |
5. Transaction and operation
- Transaction: one, only when something matched (source).
- Operation description:
delete bookmark <name1, name2, …>(source). - Commits: none created or rewritten.
jj undobrings the local bookmarks back.
6. Algorithm and invariants
The patterns are unioned into one matcher and run over the local bookmarks only
(source). So a bookmark that's already deleted, with only remote
entries left, doesn't match, and deleting it again prints No bookmarks to delete.; upstream's
test contrasts this with forget. The same bookmark matched by several patterns is deleted
once. The unmatched-name warning covers only exact names
(warn_unmatched_local_bookmarks).
Setting the local target to absent is all that happens. A tracked remote bookmark whose local
counterpart is gone becomes a pending deletion: jj git push treats "local absent, remote
tracked and present" as a deletion to send. A remote bookmark that is tracked but itself absent,
as with bookmark track on a never-pushed name, has nothing to delete, so after deletion
the name disappears entirely.
Invariants: only local bookmark entries change. No remote ref, commit or head is touched. Deletion happens for all matches or none.
7. Errors and edge cases
| Message | When | Source |
|---|---|---|
No bookmarks to delete. | No local bookmark matched. Not an error. | delete.rs |
Warning: No matching bookmarks for names: … | An exact name has no local bookmark. | mod.rs |
Failed to parse name pattern: Invalid string pattern | A pattern doesn't parse, e.g. an unclosed glob class. | revset_util.rs |
clap: missing <NAMES> | No names given. | delete.rs |
8. Worked example
From upstream's test_bookmark_delete_glob. Bookmarks
bar-2, foo-1, foo-3 and foo-4 were pushed to
origin, and foo-5 is tracked but never pushed. Then
jj bookmark delete 'foo-[1-3]' prints Deleted 2 bookmarks., and
jj bookmark delete foo-4 foo-* foo-* deletes the remaining two:
Upstream's bookmark listing afterwards (source):
bar-2: qpvuntsm 8e056f6b (empty) commit
@origin: qpvuntsm 8e056f6b (empty) commit
foo-1 (deleted)
@origin: qpvuntsm 8e056f6b (empty) commit
foo-3 (deleted)
@origin: qpvuntsm 8e056f6b (empty) commit
foo-4 (deleted)
@origin: qpvuntsm 8e056f6b (empty) commit
Running jj bookmark delete 'foo-[1-3]' a second time prints No bookmarks to delete.,
because the local entries no longer exist.