jj v0.39.0 released

96 points by ucirello a day ago on lobsters | 22 comments

dpassen | a day ago

jj bookmark advance automatically moves bookmarks forward to a target revision (defaults to @) using customization points revsets.bookmark-advance-from and revsets.bookmark-advance-to. It is heavily inspired by the longstanding community alias jj tug.

Glad to see this standardized and provided!

winter | 23 hours ago

+1! I’ll definitely still have an alias to tug, though. ;)

By the time I'm ready to push I'm always on a new commit past the place I want to put the bookmark, so my tug goes to @-. Definitely keeping the alias.

I've been using jj for a while, but I still don't get the usecase tug aliases solved, and at this point I'm too afraid to ask.

willhbr | 20 hours ago

You do some work, you make a bookmark to create a PR. You get some comments and make a new commit addressing those comments. Now you want the bookmark to point to the new commit, rather than the original commit. jj tug just gives a convenient way to move bookmarks up to more recent revisions.

It's also useful if you're just dumping changes straight to main and want to advance main up to the latest commit before you push.

This is less necessary if you're persistently amending a commit in response to comments.

So, is it just a shortcut for this, more or less?

jj new $bookmark
jj b s $bookmark

satvikberi | 19 hours ago

Yes, but you don't have to remember the bookmark name. Which is nice because a lot of workflows involve those names being autogenerated, e.g jj git push -c @. jj tug just moves the nearest bookmark amongst the parents

willhbr | 19 hours ago

In essence yes, but you don't have to type the bookmark name, and you do it retroactively. Not typing the name is nice if you're using the auto-generated bookmark names for PRs.

The alias that I have configured that I got from here is:

[aliases]
tug = ["bookmark", "move", "--from", "heads(trunk()::@ & bookmarks())",
  "--to", 'latest(trunk()::@ ~ description(exact:"") ~ empty())']

This moves any bookmarks in the parent chain (rather than just one level up) up to the most recent non-empty commit.

Oh, the autogenerated bookmarks are a good point for this. Having to fit into existing branch naming conventions, I've been unable to avoid naming my bookmarks.

chinmay | 15 hours ago

why @ instead of @- though

kingmob | 15 hours ago

Probably because @ might not be empty. I have a revset alias I use with jj tug: 'closest_nonempty(to)' = 'heads(::to ~ (empty() ~ merges()))'

Given a target single change ID to, it will return to if it's not empty, or the parent if it is. It's a hack, but works in most situations (can't handle merges).

kingmob | 14 hours ago

I misremembered, I'm actually tugging to 'closest_pushable(to)' = 'heads(::to & mutable() & ~description(exact:"") & (~empty() | merges()))'

senekor | 9 hours ago

Cool, I stole this. Without the & (~empty() | merges()) though, I find it a little restrictive. Sometimes, I create empty WIP commits that serve as a kind of TODO on the remote. So I may actually want to push empty, non-merge commits.

chinmay | 12 hours ago

Probably because @ might not be empty.

it's usually empty whenever i run tug (which is just before a push). but your closest_pushable alias is even nicer thanks

DanOpcode | 23 hours ago

jj bookmark advance and jj arrange sound like great additions! I'm eager to try them out!

been waiting for jj arrange from the time i started using it!

viraptor | 17 hours ago

It sounds like it can completely take over the need for jjui for me. I'm glad it's all in one place now.

senekor | 15 hours ago

They didn't make it in the highlights apparently, but IMO fileset aliases would've been a strong candidate, too. Cargo.lock in the diff is usually just noise, having an alias to filter that out is a blessing!

ilyagr | 15 hours ago

Amazing, thanks for highlighting! The snippet from https://docs.jj-vcs.dev/latest/filesets/#aliases seems very useful:

[fileset-aliases]
'LOCK' = '**/Cargo.lock | **/package-lock.json | **/uv.lock'
'not:x' = '~x'

Then, jj diff not:LOCK or jj log -p not:LOCK and so on.

In fish, ~LOCK works fine too, btw (not sure which shells try to do user expansion. bash seems smart enough to only do it if there's a user named LOCK)

senekor | 14 hours ago

Oh, nice! I didn't know fish doesn't expand "~LOCK". I personally just made a "nolock" alias (also including uv.lock, bun.lock) directly, that seemed most simple to type for me.

krisajenkins | 15 hours ago

jj arrange is just terrific. 🏆

kingmob | 15 hours ago

Looks great! Lots of QoL improvements. Hopefully I can delete some of my hackier workarounds.

Unfortunately, what I really want at this point is support for auto-advancing bookmarks, aka git-style named branches.

Not because I think we need to name branches (we don't), but because there's too much interop friction for me from tooling that expects git, and it's gotten worse with the amount of agent-centric tooling that wants to do worktrees/branches.