In short: jj refuses if old doesn't exist, or if new already exists without
--overwrite-existing. In one transaction it points new at old's
target and removes old. For every remote where old was tracked, it starts
tracking new there, unless an untracked new already exists on that remote.
It records rename bookmark old to new, then warns that the old remote bookmarks still
need pushing.
The command is cmd_bookmark_rename. Tracking is
explained on the bookmark track
page and the deletion that follows on bookmark delete.
1. Command-line surface
| Argument | Type | Default | Meaning |
|---|---|---|---|
OLD (positional) | bookmark name | required | An existing local bookmark. Parsed as a revset symbol, so quoting rules apply; not a pattern (source, parse_bookmark_name). |
NEW (positional) | bookmark name | required | The new name (source). |
--overwrite-existing | bool | false | Allow NEW to exist already; its target is replaced (source). |
2. Configuration
None of its own. In a Git-backed repo the reserved git remote is excluded from all the
tracking logic (source,
default_ignored_remote_name). In a colocated
workspace, tx.finish exports the renamed branch to Git.
3. End-to-end flow
4. Core architecture touchpoints
| Structure | Read / write | How | Explained on |
|---|---|---|---|
View.local_bookmarks | write | new gets old's target, conflicts included; old becomes absent (source). | view |
Remote bookmarks of new | write | Marked tracked on each remote where old was; with --overwrite-existing, first untracked (track/untrack_remote_bookmark). | view |
Remote bookmarks of old | untouched | Still tracked with the local name gone, so they show as old (deleted) until pushed. | view |
| Commits | untouched | Only names move. | commits |
| Operation | write | One operation, unless it errors or is the no-op. | operations |
5. Transaction and operation
- Transaction: one, after the checks (source).
- Operation description:
rename bookmark <old> to <new>(source). - Warnings after the commit: the "not renamed" and "exist" warnings are printed after
tx.finish, so they refer to a rename that already happened (source). jj undorestores both names and their tracking state.
6. Algorithm and invariants
Moving the tracking state
For each remote bookmark named old that is tracked, outside the git remote
(source):
- If it's present, remember that tracked remote copies of
oldexist, for the warning at the end. - If
new@remotealready exists and is untracked, skip it with a warning: tracking it would merge that unrelated remote bookmark into the local one. - Otherwise call
track_remote_bookmark(new@remote), which merges the remote target into the local bookmark and marks it tracked. Whennew@remotedoesn't exist yet, it's an absent but tracked entry, which makes the nextjj git pushcreatenewon that remote.
--overwrite-existing
Before moving anything, every tracked remote bookmark of new is untracked so the transfer
starts clean (source). Afterwards, for each remote where
new was tracked and present but old wasn't tracked, jj warns
Tracking of remote bookmark new@remote was dropped. (source).
Invariants: the commit new points to is exactly old's former
target. Nothing changes on remotes until you push. The git pseudo-remote is never tracked or
untracked here.
7. Errors and edge cases
| Message | When | Source |
|---|---|---|
No such bookmark: <old> | old has no local target. | rename.rs |
Bookmark already exists: <new> | new exists and there's no --overwrite-existing. This includes renaming a bookmark to its own name: the existence check comes before the same-name check. | rename.rs, test |
Warning: Tracked remote bookmarks for bookmark <old> were not renamed., hint to push old then new, or jj git push --all --deleted | old had tracked, present remote bookmarks. | rename.rs |
Warning: Tracked remote bookmarks for bookmark <new> exist., hint Run `jj bookmark untrack <new>` … | new already has tracked, present remote bookmarks, without overwrite. Not an error, so that renaming back and forth works. | rename.rs |
Warning: The renamed bookmark already exists on the remote '<remote>', tracking state was dropped. | An untracked new@remote exists where old was tracked. | rename.rs |
Warning: Tracking of remote bookmark <new>@<remote> was dropped. | Overwriting dropped tracking that old didn't have. | rename.rs |
8. Worked example
From upstream's test_bookmark_rename. bremote was pushed
to origin and is tracked. Then jj bookmark rename bremote bremote2:
Upstream's output (source):
Warning: Tracked remote bookmarks for bookmark bremote were not renamed.
Hint: To rename the bookmark on the remote, you can `jj git push --bookmark bremote` first (to delete it on the remote), and then `jj git push --bookmark bremote2`. `jj git push --all --deleted` would also be sufficient.
Renaming back with jj bookmark rename bremote2 bremote prints
Tracked remote bookmarks for bookmark bremote exist. as a warning, not an error. After restoring,
jj git push --bookmark bremote2 reports bookmark: bremote2 [add to 1e76d54fcfce]
(source).