jj: FR: Upsert branch (update branch or create if it does not exist)

Is your feature request related to a problem? Please describe. When working with Git, I need to remember if a branch is already created before updating it.

For example, jj branch set my-branch -r @- gives a Error: No such branch error. I then need to change the command to jj branch create my-branch -r @-

Describe the solution you’d like

An option on jj branch set such as -c/--create to create the branch if it does not exist.

Example: jj branch set my branch -r @- -c

Describe alternatives you’ve considered

Writing a shell alias for jj branch set $args || jj branch create $args (pseudo-code).

About this issue

  • Original URL
  • State: open
  • Created 2 months ago
  • Comments: 15

Most upvoted comments

I’m a little late to the discussion, but we could have jj branch move to move branches (what set does now) and jj branch set to move or create branches.

(Indeed, as Waleed mentioned, I do regularly make typos and care about them)

I think there’s a good amount of reflection from @arxanas’s post, but I think there’s also one element missing: just because how people work with computers changes doesn’t mean everything should adapt. I think keeping creation and setting separate makes a lot of sense from a correctness standpoint. I’d much more strongly prefer we use --allow-new instead of --create, to encourage creating branches (or topics, or whatever they become) explicitly.

Using branch set --create as a default will lead to people blurring out the fact that they are opening themselves to creating new branches, because they’ll mentally erase --create when they think they aren’t actually going to be creating. branch set --allow-new doesn’t have the risk of seeing --allow-new as not being part of the specific context, as it’s adding permission, not changing the nature of the operation, from the user’s perspective.

My opinion on the whole create/set split is that it generally helps users like myself who tend to litter the branch names with typos. It was really nice when branch set stopped to create seemingly “correct” branches, which were just typos. I’m in general for keeping both jj branch set --create and jj branch create, as they’re a good UI. (See a previous discussion here)

I’m also in favor of renaming the current branches concept to bookmarks, as they’re totally misleading for long term Git users, and actually accurately describing the current behavior.

the typo problem is mostly addressed by requiring --allow flags for unusual movements.

The typo problem is addressed for the case when you’ve typoed a branch name but accidentally produced another valid branch name (which happens), but it doesn’t address the case when you create a new branch entirely unintentionally. (I recall cases earlier in my career where I spent some time trying to figure out, for example, why a push wasn’t doing anything, where it turned out that I didn’t actually update the branch that I thought I did, although this is somewhat mitigated by better tools for visualization.) (cc @ilyagr who I thought had complained about typos as well?)

I can’t think of any use case where we would want to throw an error when setting a branch that doesn’t exist.

The most obvious error case is when someone makes a typo in a branch name and they intended to update an existing branch.

I’m opposed to making set the default way to create branches unless

  • we determine who jj is intended to serve:
    • Does it include non-professional users, such as academics and hobbyists? Do they have the same computing idioms as we do?
      • In particular, web interfaces and mobile operating systems have significantly changed the UI landscape over the last 10-15 years, and we should expect trends to continue. There was a time when you could expect most computing users to know what a “file” is, but anecdotal reports from teachers indicate that young students no longer operate on that level of abstraction, probably due to mobile computing idioms.
  • the UI paradigm is natural for jj’s intended audience
    • Is the branch-setting behavior really intuitive, or are we just used to Git/Unix tooling being quirky like that?
      • To take an example, does it really make sense that the touch command is also a primary way to create files? Does that resemble how anyone uses the filesystem in a GUI? They are very different; only Unixbrains would consider them the same operation. I think we should re-examine many of those biases, natural to us, before we bring them into jj, which might server a broader audience.
    • Does it resemble some other similar UI metaphor already in common use? Does that metaphor match users’ mental models about branching?
      • Possible analogues: shortcuts, labels, starring/pinning, (social) sharing, virtual addressing (PO boxes, phone books), …
  • the UI paradigm is effective for jj’s intended audience
    • Making the invocation shorter (that is, jj set to create) is likely more convenient than having separate commands, so I don’t think this criterion is contended.
  • philosophically, we decide how much redundancy is “good” to have in the UI.

(Another solution is to completely drop branches as a core feature, adopt topics or something else, and stop worrying about whether the branch UI makes sense 🤣)

I think it’s okay to deprecate branch create if we add set --create/--allow-new. To me, the verb set can also mean creation, and the typo problem is mostly addressed by requiring --allow flags for unusual movements.

@joyously only from an implementation perspective, I think.

  • It’s fairly arbitrary that creating a branch happens to be the same as updating a branch. Why should that be the case from the user’s perspective?
  • If branches can diverge (that is, a single branch can potentially address multiple commits), then that’s especially reason to not consider setting and creating to be the same thing.
    • If we were used to Monotone instead of Git, then we might feel the same way naturally due to its branching approach.
  • Many situations don’t use “creating” and “updating” as the same thing. To take the “upsert” example from the title, in traditional SQL, INSERT and UPDATE are distinct operations, and you can’t use them interchangeably.
  • A certain class of Git users reports doing typos in their branch setting and not realizing it until much later, so the separation of the commands addresses a real usage problem.

I believe we’ve pretty much achieved consensus on adding --create to jj branch set, just nobody has implemented it yet.

It should be fairly straightforward to add if you want to give it a try (check the existing implementations for set and create; I wouldn’t be surprised if set had a specific check that the branch exists first, which you could just omit in this case — that’s how set used to function.)