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: When creating a branch, I'd like to be able to specify some remote(s) it can be pushed to #5472

Open
ilyagr opened this issue Jan 26, 2025 · 15 comments

Comments

@ilyagr
Copy link
Contributor

ilyagr commented Jan 26, 2025

Is your feature request related to a problem? Please describe.

I like and use the behavior where new branches are not pushed to remotes by default. In particular, I have some branches I only want to push to origin, and some I only want to push to upstream (and sometimes perhaps some that get pushed to both)1.

However, it is annoying to me that I cannot designate a branch as "this branch should be pushed to the origin" at the moment of its creation (when I usually am thinking about that).

Describe the solution you'd like

Perhaps jj branch create --track origin could create a branch that's pre-cleared to be pushed to origin, even with jj git push --tracked.

If we use this syntax, we might also want jj branch track docs-single-page@origin to work after creating the branch. Currently, it results in Error: No such remote bookmark: docs-single-page@origin

Describe alternatives you've considered

I could, of course, disable this check entirely with #5094.

We could have jj branch create --allow-push-to origin, but then it'd be less clear whether jj git push --tracked should push it.

This might introduce too much complexity to be worth implementing.

Another, possibly easier, option would be to implement jj branch create br --push-to origin that would push the branch immediately after creating it. OTOH, this would be slightly less convenient if the push fails, and it might be a good idea to keep all push/fetch functionality confined to those two commands.

I'm not sure this is possible right now, but we could have a way to make a user command alias that creates a branch and immediately pushes it.

Footnotes

  1. More details about my use-case: I usually have a feature branch that is only pushed to origin (my personal Github fork), and then at some point I create an ig/feature branch (at the same location) that I want to push (only) to upstream. different set of branches that I want to be pushed to origin.

@ilyagr ilyagr changed the title FR: When creating a branch, I'd like to be able to specify which remote(s) it can be pushed to FR: When creating a branch, I'd like to be able to specify some remote(s) it can be pushed to Jan 26, 2025
@scott2000
Copy link
Contributor

Since in jj it's common to create bookmarks immediately before pushing, maybe this could be an option to jj git push so it could all be done as a single operation? Like jj git push -c <revset> --name <name> would push the change, but it would use the supplied name instead of the default push- prefix.

Then this issue would be solved by preventing a bookmark which has already been pushed to one remote from being pushed to a different remote.

@ilyagr
Copy link
Contributor Author

ilyagr commented Jan 26, 2025

That's a good idea! It'd require me to change my workflow slightly, but not by much, and it sounds a lot easier.

@martinvonz
Copy link
Member

Isn't that #4388?

Note that jj git push -c accepts multiple revisions, so it's unclear how --name would be used. It would presumably fail if the revset had more than one revision. This is the reason for a separate command (e.g. jj git push-ref) in #4388.

@scott2000
Copy link
Contributor

I think that's a bit different because jj git push-ref would allow pushing artibtrary refs, so it presumably wouldn't create a local bookmark tracking the remote branch (since it might not even be a branch).

I think it's a lot more similar to the jj git push -c functionality, since it basically would be doing the same thing but with an explicit name. It would be strange having -c accept multiple revisions sometimes and not other times though, so I'm not sure what the best UI would be.

@ilyagr
Copy link
Contributor Author

ilyagr commented Jan 26, 2025

It would be strange having -c accept multiple revisions sometimes and not other times though, so I'm not sure what the best UI would be.

I think it'd be OK to forbid --name unless -c has a single revision. We allow repeating -c; we could also (optionally) allow repeating --name so that you get a single --name per -c (and each -c would need to expand to a single revision).

We already treat a -c argument expanding to multiple revisions specially, requiring the all: modifier (IIRC).

@ilyagr
Copy link
Contributor Author

ilyagr commented Jan 29, 2025

There are some devils in the details. Currently, my plan is to have

jj git push -c abc --name fun-branch --remote qq

fail unless either fun-branch does not exist or there is a local fun-branch located precisely at abc. The latter case is so that if the push fails, you can repeat the jj git push -c abc --name fun-branch command.

As far as the remote is concerned, we'll use the usual rules (so, if the branch already existed, fast-forwards are allowed; anything else is considered a conflict and you are told to run jj git fetch).

If the remote branch exists and is untracked, we also fail (I think this is part of the "usual rules").

Let me know if you have thoughts. Is this worth having in this form?

I've been using my draft version (without any detection of same-named branches), and it's been nice, though obviously not essential.


Another alternative would be to make it more similar to

jj bookmark set -r abc fun-branch
jj git push --allow-new --remote qq -b fun-branch

One reason I didn't like that is that it leads to a question: do we also add a --allow-backwards flag to jj git push? I don't want to do that.

Update: Also, this would create a possibility that the branch was moved but the push failed. On second thought, this seems important to avoid.


I also considered recommending a shell script that does the above two commands, but that would mess up command-line completion for revisions. If aliases were powerful enough, we could perhaps go with that.

Update: Though, again, this would create a possibility that the branch was moved but the push failed.

@yuja
Copy link
Contributor

yuja commented Jan 30, 2025

jj git push -c abc --name fun-branch --remote qq

fail unless either fun-branch does not exist or there is a local fun-branch located precisely at abc. The latter case is so that if the push fails, you can repeat the jj git push -c abc --name fun-branch command.

If push failed within the same transaction, the created local bookmark would also disappear. So I think we can just recreate the same bookmark as -c (without --name) would do?

FWIW, I don't like the UI that we have to pair up -c and --name, but I don't have a better idea. --name could be a template, but it would be useful only when the user wants to give different prefix/suffix other than push-{id}.

@ilyagr
Copy link
Contributor Author

ilyagr commented Jan 30, 2025

If push failed within the same transaction, the created local bookmark would also disappear.

Ah, that's nice, good point!

So, perhaps we can require the bookmark to not exist. I'm not sure whether or not there's harm in allowing the bookmark to exist at that commit, but not allowing it makes for easier code; we could start with that.

So I think we can just recreate the same bookmark as -c (without --name) would do?

What do you mean?

FWIW, I don't like the UI that we have to pair up -c and --name, but I don't have a better idea.

+1

One possibility would be to assume -c @ if --name is used, but I'm worried this would cause confusion about what --name does, and it would contradict the idea of requiring @ to be explicit for bookmark set.

--name could be a template, but it would be useful only when the user wants to give different prefix/suffix other than push-{id}.

If I understand the idea correctly, we could add this in the future (using some sort of template that uses a character uncommon in bookmark names), or this could be a separate --name-prefix or --name-template option.

@scott2000
Copy link
Contributor

Maybe it would be better if jj git push took a revset argument, and then --change and --create-bookmark were just flags to specify how to push the revset? Something like this:

# Push bookmarks in default revset
jj git push
# Push bookmarks in specified revset
jj git push REVSET
# Create bookmark based on change ID at revset
jj git push REVSET --change
# Create bookmark at revset with given name
jj git push REVSET --create-bookmark NAME

I'm not sure how well it would interact with --bookmark, --all, --tracked, and --deleted though. Probably some options would be mutually exclusive with REVSET, and --create-bookmark would require the revset to evaluate to only a single revision. It would be backwards compatible I think, because jj git push -c REVSET would still be valid (but the parsing would change), and we could add a dummy -r flag to keep jj git push -r REVSET valid too.

@ilyagr
Copy link
Contributor Author

ilyagr commented Jan 30, 2025

There is also the distinction between "pushing every commit in a revset" and "pushing every bookmark in a revset". Currently, -c does the former and -r does the latter. We probably want to maintain this somehow, though perhaps there could be some short way to intersect a revset with bookmarks() (IIRC the name correctly).

--tracked and --all have more to do with -b, which is a third category, since the same revision can have multiple bookmarks.

@yuja
Copy link
Contributor

yuja commented Jan 30, 2025

So I think we can just recreate the same bookmark as -c (without --name) would do?

What do you mean?

I just meant the same rule as -c could apply to -c + --name. (Oh, but -c allows to move existing bookmarks, which seemed a bit weird.)

FWIW, I don't like the UI that we have to pair up -c and --name, but I don't have a better idea.

+1

One possibility would be to assume -c @ if --name is used, but I'm worried this would cause confusion about what --name does, and it would contradict the idea of requiring @ to be explicit for bookmark set.

I agree it would be more confusing. My point was that -c can be resolved to multiple revisions, so the same number of --name arguments have to be specified, and the order matters. That's scary.

--name could be a template, but it would be useful only when the user wants to give different prefix/suffix other than push-{id}.

If I understand the idea correctly, we could add this in the future (using some sort of template that uses a character uncommon in bookmark names), or this could be a separate --name-prefix or --name-template option.

It's just to avoid "N change revisions" + "N name arguments" problem. The template argument would override the default push-{id} template. It probably works, but the use case would be different.

@ilyagr
Copy link
Contributor Author

ilyagr commented Jan 30, 2025

Oh, but -c allows to move existing bookmarks, which seemed a bit weird.

Yeah, I didn't fully think it through and follow the logic, but I think -c currently makes different choices because the bookmark name it chooses is likely to be random and unique.

My point was that -c can be resolved to multiple revisions

For now, my plan is to require it to expand to a single revision when --name is used. See also #5472 (comment) for a further (slightly weird) possibility.

@martinvonz
Copy link
Member

For now, my plan is to require it to expand to a single revision when --name is used.

It could also be separate arguments like jj git push --create-bookmark-target=@ --create-bookmark-name=my-feature (but with better names).

I think it's best to make it work only with -r and not with -c.

See also #5472 (comment) for a further (slightly weird) possibility.

We don't do anything like that anywhere else so I think it would be quite surprising.

@yuja
Copy link
Contributor

yuja commented Jan 30, 2025

It could also be separate arguments like jj git push --create-bookmark-target=@ --create-bookmark-name=my-feature (but with better names).

or single argument taking both name and revision --create-bookmark=NAME=REVSET?

@martinvonz
Copy link
Member

Yes, that seems much better, especially since it can be repeated and be combined with the existing -c/-r/-b!

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

No branches or pull requests

4 participants