jj icon indicating copy to clipboard operation
jj copied to clipboard

FR: cli option consistency

Open doy opened this issue 10 months ago • 14 comments

Is your feature request related to a problem? Please describe. a lot of jj commands do something to two different revisions, but it is very hard to remember how to do this because there are quite a few different ways that different commands specify them (for instance, from a quick browse of the manual, jj restore uses --from/--to, jj squash uses --from/--into, jj backout uses --revisions/--destination, and jj rebase uses --source/--destination).

additionally, for commands that act on a single revision, it's pretty split between whether that revision must be passed as a plain arg or through --revision.

currently i have to look up the correct option names in either the manual or my shell history pretty much every time i run one of these commands, which doesn't feel great.

Describe the solution you'd like it'd be really helpful to standardize on a single way to refer to the commits that operations will act on. i don't really have a preference other than that it'd be great if it could be more consistent across different commands.

doy avatar Jan 19 '25 08:01 doy

  • There are several semantic differences between the option names, in such a way that they are meant to be consistent, but I forget the nuances.
    • For example, jj rebase -r X exists and i is different from jj rebase -s, but generally consistent with other -r commands. (It's roughly the same as jj rebase -r 'X::'?)
  • I believe that every command which takes a positional revision argument also accepts it via -r for redundancy; file a bug if not.
    • For example, you can write jj new -r X to mean the same as jj new X.

arxanas avatar Jan 19 '25 09:01 arxanas

Funny timing with #5394 from less than a day ago. As @arxanas said, there are semantic differences between some of them.

additionally, for commands that act on a single revision, it's pretty split between whether that revision must be passed as a plain arg or through --revision.

The reason is that we currently prefer to let positional arguments mean paths. So commands that accept paths (either currently or conceivably) require the revision to be passed via -r. We have #2554 and #3809 about that.

  • For example, you can write jj new -r X to mean the same as jj new X.

That's actually an interesting case. I feel like it should accept -d but not -r because it creates the new commit on top of the argument. We talked about this on Discord a while ago. EDIT: We actually allow -d already.

martinvonz avatar Jan 19 '25 14:01 martinvonz

i can see --to and --into having different meanings (although it's still hard for me to remember) but what is the intended difference between --from/--source and --to/--destination? i don't really have a good sense of what these semantic differences are supposed to be, and i can't find anything written about it. can you point me to somewhere that describes it?

also, the docs for jj rebase say that -r only rebases the one specific commit - were you thinking of -b or am i confused?

also, if it is intended that -r works everywhere, at the very least the documentation doesn't give any indication of this (for instance, jj abandon and jj describe don't mention -r at all).

doy avatar Jan 19 '25 16:01 doy

--destination is when you are putting commits on top of an existing commit (e.g. rebase, new, backout, duplicate). --into is when you are modifying the commit itself. It’s about identifying the commit to modify vs. identifying “gaps” to fill in in the commit graph. I personally find that distinction intuitive and appreciate it; OTOH --to vs. --into is a bit of a mess (in part because it’s not clear what the --from corresponding to --into should be; --out-of is the best proposal I’ve heard, but it’s long).

jj rebase -r can take a multi‐commit revset these days. I think the documentation is out of date.

Edit: And --source identifies an entire tree of commits by its base (e.g. jj rebase -s BASE-OF-STACK -d 'main()'); I admit this name isn’t good but can’t immediately think of a better one. I believe that jj rebase -s X is the same as jj rebase -r X::, but I may be wrong.

emilazy avatar Jan 19 '25 16:01 emilazy

i don't really have a good sense of what these semantic differences are supposed to be, and i can't find anything written about it. can you point me to somewhere that describes it?

We don't have such documentation yet. I suppose we could write some new doc about the CLI design philosophy in general. A less general but quicker solution would be to add an FAQ item or two.

jj rebase -r can take a multi‐commit revset these days. I think the documentation is out of date.

Yes. I'll try to send a patch for that.

I believe that jj rebase -s X is the same as jj rebase -r X::, but I may be wrong.

You're not.

martinvonz avatar Jan 19 '25 17:01 martinvonz

I believe that jj rebase -s X is the same as jj rebase -r X::, but I may be wrong.

You're not.

But only assuming X is a single commit. If X is multiple commits, then jj rebase -s X will rebase each commit in the set onto the destination, while jj rebase -r X:: will preserve internal dependencies in the set.

martinvonz avatar Jan 19 '25 17:01 martinvonz

See if https://github.com/jj-vcs/jj/pull/5400 helps clarify how the rebase flags work.

martinvonz avatar Jan 19 '25 17:01 martinvonz

Another little case of possible inconsistency is jj backout.

I might be wrong, but I think the English phrasal verb is "back out, not backout, so the command should be jj back-out, with a separating dash just like in jj simplify-parents. The same could probably apply to jj interdiff`.

Anyway, given the fact that jj backout's manual states:

Apply the reverse of a revision on top of another revision

I don't get why the command is not simply jj reverse.

arialdomartini avatar Feb 13 '25 12:02 arialdomartini

I think it's backout because of Mercurial heritage. I would prefer revert, which seems equally accurate and less awkward.

emilazy avatar Feb 13 '25 13:02 emilazy

revert is confusing for hg users (hg revert is jj restore). We could still use that, or we could use reverse. Another option is rollback (or roll-back to be more grammatically correct).

martinvonz avatar Feb 13 '25 13:02 martinvonz

Started a separate issue, specifically related to jj backout @ https://github.com/jj-vcs/jj/issues/5688 for anyone interested in discussing in more detail!

zx8 avatar Feb 13 '25 17:02 zx8

I am still learning (and loving) jj, so I'm far from being fluent. On the contrary, I'm that sweet point in time where I am sensitive to what is intuitive vs what is not. When I will be eventually fluent with it, I will just get used to inconsistencies and I won't see them anymore.

So far, as a completely noob, I can only second @doy's observation: moving back and forth from jj restore to other commands, I find myself consulting over and over the man pages and the shell history to figure out when to use -f/-t, when -r, when -t.

I am sure I will develop an intuition on the logic. Either

  • more consistency
  • or a little section in the manual explaining the rule of thumb when to use what option

would improve my overall experience (which is amazing, anyway)

arialdomartini avatar Feb 13 '25 17:02 arialdomartini

Thanks for your feedback. I feel like this feature request has too large scope. It might be more productive to file separate feature requests for each concrete suggestion instead.

martinvonz avatar Feb 13 '25 17:02 martinvonz

As others have said, CLI arg inconsistency gets confusing. Some quick suggestions:

  • Always interpret -r as a REVSET not a REVISION. Further to this, deprecate rebase --revisions and squash --revision (etc.) in favour of --revset.
  • The above might allow deprecating squash --from, rebase --source.
  • Deprecate -d / --destination, --to, --into. Use -t / --target to replace all of these.

(I'm sure these suggestions are imperfect — don't have a lot of time to consider the implications.)

dhardy avatar Jun 12 '25 08:06 dhardy

I found it odd that jj duplicate did not have the same -s and -b options that rebase had. This forced me to learn how revset language worked, where I didn't need to know that for rebase.

joshka avatar Jul 31 '25 07:07 joshka