In short: jj matches the patterns against every bookmark name, local or remote. In one transaction, for
each match it sets the local target to absent. For each of its remote bookmarks it either forgets it
(--include-remotes) or marks it untracked, except the special git remote,
which is left alone. It prints how many local and remote bookmarks were forgotten and records
forget bookmark <names>.
The command is cmd_bookmark_forget. Compare
jj bookmark delete, which keeps
remote bookmarks tracked so the deletion gets pushed. The help text explains the untracking: it ensures
"the forgotten bookmark will not impact remotes on future pushes" (source).
1. Command-line surface
| Flag | Type | Default | Meaning |
|---|---|---|---|
NAMES (positional) | name patterns, required | — | Bookmarks to forget, matched against local and remote names; globs by default (source). |
--include-remotes | bool | false | Forget the matching remote bookmarks too, instead of untracking them. A later fetch recreates them if they still exist on the remote (source). |
2. Configuration
None of its own. In a Git-backed repo, remote bookmarks under the reserved remote name git
(the colocated Git repo's own refs) can't be untracked, so they're skipped unless
--include-remotes is given (source,
default_ignored_remote_name).
remotes.<name>.auto-track-bookmarks matters afterwards: a re-fetched bookmark may be
tracked again automatically.
3. End-to-end flow
4. Core architecture touchpoints
| Structure | Read / write | How | Explained on |
|---|---|---|---|
View.local_bookmarks | write | Set to absent for every match (source). | view |
Remote bookmarks (RemoteRef) | write | Either replaced by RemoteRef::absent(), or kept with state set to New, meaning untracked (set_remote_bookmark, untrack_remote_bookmark). | view |
View.git_refs | untouched | Upstream's test notes that keeping the Git-tracking record is why a forgotten bookmark isn't resurrected by jj git export then import (source). | view |
| Commits | untouched | Nothing is abandoned. | commits |
| Operation | write | One operation if anything matched. | operations |
5. Transaction and operation
- Transaction: one, only when something matched (source).
- Operation description:
forget bookmark <name1, name2, …>, listing every matched name (source). - Commits: none created or rewritten.
jj undorestores the bookmarks and their tracking state.
6. Algorithm and invariants
find_forgettable_bookmarks iterates
view.bookmarks(), which yields each bookmark name with its local target and all its
remote refs, and keeps names the pattern matcher accepts. So a bookmark that only exists remotely, or a
deleted one, still matches, unlike with delete. The unmatched-name warning counts a name
as present if it exists locally or on any remote (source).
For each match (source):
- The local target is set to absent; it counts toward "local bookmarks" only if it was present.
- With
--include-remotes, every remote ref, includinggit's, is set to absent and counted. - Otherwise refs on the
gitremote are skipped, and the rest are untracked: their target stays, but their state becomesNew, sojj git pushno longer pairs them with a local bookmark.
Invariants: forgetting never schedules a push. Without --include-remotes,
remote targets are kept, so jj git fetch reports nothing new. With it, a fetch re-creates
them as new remote bookmarks.
7. Errors and edge cases
| Message | When | Source |
|---|---|---|
No bookmarks to forget. | No name matched anywhere. | forget.rs |
Forgot N local bookmarks. / Forgot M remote bookmarks. | Status lines, each only when its count is non-zero. | forget.rs |
Warning: No matching bookmarks for names: … | An exact name exists neither locally nor on any remote. | mod.rs |
Failed to parse name pattern: …, hint listing pattern kinds | A pattern doesn't parse. | revset_util.rs |
clap: missing <NAMES> | No names given. | forget.rs |
8. Worked example
From upstream's test_bookmark_forget_fetched_bookmark, with
remotes.origin.auto-track-bookmarks = '*'. feature1 is fetched from
origin and tracked. The test forgets it both ways:
When the bookmark had moved on the remote before being forgotten with --include-remotes, upstream shows (source):
Forgot 1 local bookmarks.
Forgot 1 remote bookmarks.
$ jj git fetch --remote=origin
Fetching from Git remotes: origin
bookmark: feature1@origin [new] tracked
As the test's comment puts it, "Fetching a moved bookmark does not create a conflict": the bookmark simply comes back at its new position.