Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FR: Convenient names for changes #3482

Open
matts1 opened this issue Apr 10, 2024 · 18 comments
Open

FR: Convenient names for changes #3482

matts1 opened this issue Apr 10, 2024 · 18 comments
Labels
enhancement New feature or request

Comments

@matts1
Copy link
Collaborator

matts1 commented Apr 10, 2024

Is your feature request related to a problem? Please describe.
There are two related problems here that this FR is designed to solve:

  1. Naming local commits - it becomes very annoying to remember change IDs and/or revsets, and so if you name commits it can be a lot easier to write jj new <alias>
  2. Identifying commits for the purposes of patch-based workflows. In a patch-based workflow such as internally at google, or gerrit, it'd be useful to be able to see in my jj log entries such as:
@  vzokzlpu msta 5 days ago crrev.com/c/5439098 a2016214
│ Commit description here

Similarly, it'd be nice to be able to write crrev.com/c/5439098

Describe the solution you'd like
I'd like to add a command jj alias. This would be almost the same command as jj branch - it would have the following subcommands:

  • jj alias add <revision> <alias> --force
    • --force would move the alias to here even if it was previously defined elsewhere
  • jj alias remove <alias>

Aliases would be associated with a change, and thus would persist across rewrites. The main distinction between aliases and branches are that:

  • They would not be represented in git
  • When you drop the commit, the alias would disappear too, rather than propogating to the parent

Similar to branches, you could write jj alias add @- foo, then later run jj new foo

Describe alternatives you've considered
Branches
When I asked about this earlier, branches are the currently recommended solution for such an approach. However, the problem is that a branch is not associated with a particular change. Consider:

◉  pvlpykyo msta 5 days ago foo 13bbdfc2
│  My local commit
◉  vzokzlpu msta 5 days ago main a2016214
│  immutable head here

If I were to write jj abandon foo, then the branch foo would instead move to main. The same thing would happen if I were to submit foo, then later run jj rebase --skip-empty.

Tags:
I considered just using git tags for this, and just calling them tags, but @martinvonz pointed out that might be confusing since tags are associated with a commit, rather than a change.

Additional context
Add any other context or screenshots about the feature request here.

@torquestomp
Copy link
Collaborator

Some initial thoughts:

  • I don't like the name 'alias', I think something like 'name' or 'label' or something else would be better. 'alias' is already well defined in config.toml and it's about something entirely different
  • What happens if I run jj alias add <commit2> foo when foo is already associated with a separate <commit1>? Since these are already going to behave differently from branches, does it make sense to allow multiplicity here too?

@matts1
Copy link
Collaborator Author

matts1 commented Apr 10, 2024

Discord thread

@matts1
Copy link
Collaborator Author

matts1 commented Apr 10, 2024

  • I don't like the name 'alias', I think something like 'name' or 'label' or something else would be better. 'alias' is already well defined in config.toml and it's about something entirely different

I'm not opposed to changing the name if we can find a good alternative. I personally don't like "name", since I don't think crrev.com/c/123456 is really a name. I wouldn't be opposed to label. I definitely like alias the most, but as you said, it's overloaded, which I hadn't considered when making this proposal.

  • What happens if I run jj alias add <commit2> foo when foo is already associated with a separate <commit1>? Since these are already going to behave differently from branches, does it make sense to allow multiplicity here too?

It would throw an error and say that you can use --force to move the alias. Multiplicity doesn't make sense here, since the whole point of this is to be able to use the alias as an alias for a specific commit. A major thing of these aliases is that you need to be able to write, for example, jj new <alias>.

I don't see a particularly strong use case to justify multiplicity, but if we decided that we did want to support it, IMO the best way would be to have the label, when created, specify whether it supported multiple changes being associated with it.
jj label add --multiple @- foo, which would not complain about adding a label that already exists.

@yuja
Copy link
Collaborator

yuja commented Apr 11, 2024

Describe alternatives you've considered Branches When I asked about this earlier, branches are the currently recommended solution for such an approach. However, the problem is that a branch is not associated with a particular change. Consider:

◉  pvlpykyo msta 5 days ago foo 13bbdfc2
│  My local commit
◉  vzokzlpu msta 5 days ago main a2016214
│  immutable head here

If I were to write jj abandon foo, then the branch foo would instead move to main. The same thing would happen if I were to submit foo, then later run jj rebase --skip-empty.

This is sometimes annoying for real branches, so it would be nice if we had an option or config knob to abandon commit as well as the associated branches.

I'm not sure if we'll need new "alias"/"label" concept. Since jj doesn't have the current/HEAD branch, branches are conceptually bookmarks to changes. Aliases could be considered sticky variant of the branches/bookmarks.

@martinvonz
Copy link
Member

This is sometimes annoying for real branches, so it would be nice if we had an option or config knob to abandon commit as well as the associated branches.

A CLI option makes sense to me. If we had a config option, I suppose the idea is that it makes sense for some workflows, which sounds reasonable. I think it does make sense for users of the integration at Google.

I'm not sure if we'll need new "alias"/"label" concept. Since jj doesn't have the current/HEAD branch, branches are conceptually bookmarks to changes. Aliases could be considered sticky variant of the branches/bookmarks.

What do you mean by "sticky variant"? It seems reasonable to model them as a flag attached to a branch to say that the branch should be abandoned if the commit is abandoned. I suspect that's not what you mean by "sticky variant" because it doesn't sound like it's about stickiness.

@yuja
Copy link
Collaborator

yuja commented Apr 11, 2024

What do you mean by "sticky variant"? It seems reasonable to model them as a flag attached to a branch to say that the branch should be abandoned if the commit is abandoned.

Exactly it. Perhaps "sticky" isn't the right word. I used it meaning the bookmark sticks to the change, and will never slide down when abandoned.

@PhilipMetzger PhilipMetzger added the enhancement New feature or request label Apr 11, 2024
@joyously
Copy link

meaning the bookmark sticks to the change, and will never slide down when abandoned.

Yet there is a PR for a flag to make branches move, so pushes to Git are easier, and Mercurial has bookmarks.
This sounds like another example of mixing implementation details into the UI. The revset page says

Jujutsu attempts to resolve a symbol in the following order:
Tag name, Branch name, Git ref, Commit ID or change ID

Maybe the docs should be clarified as to the jj way regarding branches (are they only for Git interop?), tags (do they exist or only in Git?), commit IDs (why expose this by default?).
Is jj its own VCS, or just another interface to Git? Once that is decided, the standard VCS way of attaching names to versions will become clearer.

@martinvonz
Copy link
Member

Is jj its own VCS, or just another interface to Git? Once that is decided, the standard VCS way of attaching names to versions will become clearer.

jj is definitely its own VCS. Git is not involved in the integration we have at Google, for example. It's also not used for jj's native backend. Any reason to think it's just an interface for Git? Did our docs indicate that somewhere? We should update them in that case.

@thoughtpolice
Copy link
Collaborator

thoughtpolice commented Apr 11, 2024

jj is definitely its own VCS. Git is not involved in the integration we have at Google, for example. It's also not used for jj's native backend. Any reason to think it's just an interface for Git? Did our docs indicate that somewhere? We should update them in that case.

I think Joy is asking the question rhetorically, in order to reframe the discussion in a different light.

If jj isn't a wrapper to Git, then why are branches and their behaviors, such as automatic movement — a somewhat uniquely "Git" "idea" — exposed in the top-level UI? We have said multiple times (in Discord, here, elsewhere) that branches are mostly of small utility in the world of anonymous heads, where most operations revolve around the commit graph. We only really have them exposed so much because all our users are Git users, and Git users need branches to do their work.

So, today they are used only for Git interop. Yet if they are exposed as a first-class concept in the UX like they are now, this makes other related features awkward to phrase and design around. This FR itself, as far as I can tell, is quite literally just asking for "bookmarks" as Mercurial calls them. The whole feature could be realized and implemented if you could do jj new --bookmark my-bookmark-name and we'd be done with it. But if we already have jj branch, it sort of suffocates the design space of the UX. What's the difference between branches and bookmarks? Why would you use one over the other? Does the native jj backend or CitC backend use branches? Then you might even get into more "bottom-up" questions that are even further from the point, such as implementation details: are branches just bookmarks with an auto_advance=True flag? Are they "sticky branches" which get deleted on abandon? By this point we're far off the mark, I think, because we are talking about it from the bottom-up, rather than designing from the top-down.

If they aren't regularly used or intended to be used outside of Git, what's even the point of putting them in the top level?

Realistically, this is reminding me of the jj init --git ordeal, #2747. The UX we have now might be flawed, and this is impacting our understanding of the problem and solution space, perhaps. If branches as they are only exist for Git interoperability, why do we even have a top-level jj branch command? If we called it jj git branch instead and shoved all the million behaviors behind it, it would be clear, from a top-down point-of-view, what its relationship to other things are. We could then have jj bookmark as a top-level command instead, and it would be much more clear what value it provides, independently of the backend.

Just to be clear, I haven't thought about this actual FR very much. I'm thinking out loud and maybe we're all in violent agreement, actually. I would also like some behavior like this, because it would be useful to gerrit send, and maybe even help carve a path to something like Sapling's "Super SmartLog" which can e.g. show status of a code review from the log (e.g. if remote_gerrit_instance_url is prefix of (any bookmarks of revision c), then display_enriched_commit_info). But I think this may be a case where we need to go back to square 1 and think about how these things even relate.

@matts1
Copy link
Collaborator Author

matts1 commented Apr 11, 2024

FWIW, I had a chat with a few people who were curious about jj, but were git users, a while ago.

They saw value in jj, but one of the things that they really didn't like is that jj's concept of branches doesn't really map to git's concept of branches very well.

IMO, @thoughtpolice's idea of turning jj branch into jj git branch would be a good solution to this, to make it clear that whatever this FR ends up being is the jj way of doing it. I don't personally see any workflow in which in which branches moving to their parent automatically, but aren't being "tracked" in the same way git does is useful (but maybe I'm wrong and just haven't thought of it yet - if anyone has use cases I'd like to know).

Alternatively, if we did decide that it's not useful to propogate to the parent, maybe we should just delete branches when jj deletes a change? That might be a bit too radical of a decision though?

@joyously
Copy link

Any reason to think it's just an interface for Git? Did our docs indicate that somewhere?

I read a bunch of the docs today. One thing that is in there is that there are two backends: one with Git and a native one that you can't use. All the explanations compare and contrast with Git. I didn't see anything proving that it's a stand-alone VCS.

I think Joy is asking the question rhetorically, in order to reframe the discussion in a different light.

Not rhetorically, but also not nearly as well said as you put it.

idea of turning jj branch into jj git branch would be a good solution to this

I don't see how that would solve the original question. What you asked for was a tag. The way a jj branch is defined today is a tag. Both have the behind-the-scenes-but-not-hidden Git in the way of defining a clear jj interface using those familiar terms.

@matts1
Copy link
Collaborator Author

matts1 commented Apr 12, 2024

I don't see how that would solve the original question.

Sorry, upon rereading it, it seems badly phrased. What I was trying to say was that if we implemented this FR, then I think we should try and imply to the user that they should be using this FR rather than branches, and that jj git branch would tell the user that branches aren't really a thing you should be using with jj, but rather a remnant of git.

@yuja
Copy link
Collaborator

yuja commented Apr 12, 2024

IMO, @thoughtpolice's idea of turning jj branch into jj git branch would be a good solution to this, to make it clear that whatever this FR ends up being is the jj way of doing it. I don't personally see any workflow in which in which branches moving to their parent automatically, but aren't being "tracked" in the same way git does is useful (but maybe I'm wrong and just haven't thought of it yet - if anyone has use cases I'd like to know).

Just to be clear, Mercurial's bookmark does move backwards if the attached commit get discarded. Maybe it's designed with topic branches in mind?

Anyway I don't think the current jj branches are Git thing, but backend agnostic.

@PhilipMetzger
Copy link
Collaborator

I dislike adding another feature for naming revisions, as we already have a branch/bookmark concept. I do want to support the use-case @matts1 talks about but I'd start with gerrit send (#485 ) and then building backwards and finishing the work with a hg xl or Sapling-like SuperSmartLog.

I've noted before that our branches currently are very user-unfriendly (and not what a Git user expects) and would rather move to #3402 for our own equivalent of the named set of commits, which Git branches encompass.

@arxanas
Copy link
Collaborator

arxanas commented Apr 14, 2024

  • When you drop the commit, the alias would disappear too, rather than propogating to the parent
  • This is sometimes annoying for real branches, so it would be nice if we had an option or config knob to abandon commit as well as the associated branches.

I don't think branches should slide backwards to begin with. git-branchless deletes the branch, and I'm actually surprised to hear that Mercurial slides it backwards. Sapling also deletes the branch (regardless of whether you address the commit via hash or branch):

$ sl
o  08f7e40d5  47 seconds ago  me  bar
│  Create bar
│
@  fa0a72a14  57 seconds ago  me
   Initial commit

$ sl hide bar
hiding commit 08f7e40d5245 "Create bar"
1 commit hidden
removing bookmark 'bar' (was at: 08f7e40d5245)
1 bookmark removed
hint[undo]: you can undo this using the `sl undo` command
hint[hint-ack]: use 'sl hint --ack undo' to silence these hints
$ sl
@  fa0a72a14  65 seconds ago  me
   Initial commit

$ sl undo
undone to Sun Apr 14 15:15:28 2024 -0700, before hide bar
$ sl
o  08f7e40d5  60 seconds ago  me  bar
│  Create bar
│
@  fa0a72a14  70 seconds ago  me
   Initial commit

$ sl hide 08f7e40d5
hiding commit 08f7e40d5245 "Create bar"
1 commit hidden
removing bookmark 'bar' (was at: 08f7e40d5245)
1 bookmark removed
hint[undo]: you can undo this using the `sl undo` command
hint[hint-ack]: use 'sl hint --ack undo' to silence these hints
$ sl
@  fa0a72a14  75 seconds ago  me
   Initial commit
  • Who does the sliding-branch behavior benefit, anyways?
  • I think we should just change jj branches to not do that.
  • This weird behavior can happen during e.g. git rebase, but I think it's largely an implementation detail of the fact that it literally applies commits in sequence, and inherits Git branching behavior while doing so, rather than that sliding backwards makes sense.
    • There might be some cases where we deduplicate commits (by patch ID or something else) but still want to keep a topic branch around for the remaining commits, but
      • I would like to see the explicit deduplication behavior be part of jj git sync rather than jj rebase,
      • and I think the behavior is sufficiently weird that it would overall be best to just delete the branches anyways in such cases, rather than have the user try to remember the specific cases where branches slide backwards vs get deleted.

@arxanas
Copy link
Collaborator

arxanas commented Apr 14, 2024

The main distinction between aliases and branches are that:

  • They would not be represented in git
  • When you drop the commit, the alias would disappear too, rather than propogating to the parent

I think neither are the case for topics, either. @matts1 can you compare/contrast with topics as described there? Do they solve your problem?

@matts1
Copy link
Collaborator Author

matts1 commented Apr 14, 2024

I don't think branches should slide backwards to begin with.

If we changed the behaviour to this, I'd be perfectly happy to close this FR as unnecessary. I'd prefer just changing the behaviour over this FR, actually. I might pull this out into a seperate discussion.

can you compare/contrast with topics as described there? Do they solve your problem

The primary differences between this and topics would be:

  • Only one change per name
  • Not "infectious", as described in that FR

@neongreen-sc
Copy link

Another usecase for labels (or any other per-change metadata): I could mark "important" commits with a label.

For example, if someone made a commit with a change that I wanted to make, and then went on vacation, I'd like this commit to hang out in my jj log so that it doesn't get lost even if the PR author gets hit by a bus.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

9 participants