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

cli: git push: exclude new bookmarks tracking other remotes if no --remote set #4730

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

yuja
Copy link
Collaborator

@yuja yuja commented Oct 29, 2024

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added tests to cover my changes

Copy link
Owner

@martinvonz martinvonz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable. I've never run into this problem, but I rarely use more than one remote. Maybe we can ask on Discord if others have any opinion.

cli/src/commands/git/fetch.rs Outdated Show resolved Hide resolved
@jennings
Copy link
Collaborator

Am I understanding this feature correctly?

$ jj git remote add origin ...
$ jj git remote add upstream ...
$ jj bookmark create foo

# pushes foo to upstream and tracks it
$ jj git push -r @ --remote upstream

# this is the new behavior:
# this does nothing since foo@upstream is tracking
$ jj git push -r @

# pushes foo to origin if the remote is mentioned explicitly
$ jj git push -r @ --remote origin

If I'm understanding this right, the goal seems reasonable but using --remote as the override seems a little obscure to me. My first guess would be that specifying the bookmark with -b was the way to do that.

@yuja
Copy link
Collaborator Author

yuja commented Oct 30, 2024

but using --remote as the override seems a little obscure to me.

Yes. That's why I added a hint saying "... Use --remote=origin to push to new remote."

My first guess would be that specifying the bookmark with -b was the way to do that.

That seemed scary. User might expect the bookmark would be pushed to the associated remote as git push would do.

This forces us to think about which repo should be used. It doesn't matter in
find_bookmarks_to_push() because moved "push-{change_id}" bookmarks are
prioritized. It doesn't matter in print_commits_ready_to_push() either, which
uses the repo only for ancestry lookup, but I think tx.repo() is better here.
…emote set

If you have multiple remotes to push to, you might want to keep some changes
in your private fork. Git CLI has one upstream remote per branch, but jj
supports multiple tracking remotes, and therefore "jj git push" can start
tracking new remotes automatically.

This patch makes new bookmarks not eligible for push if tracked bookmarks
already exists on other remotes. I considered adding a warning, but it's not
always possible to interrupt the push shortly after a warning is emitted. This
check can be turned off by specifying --remote=NAME explicitly. Another stricter
(and simpler in terms of implementation) idea is to force user to pass
--new-bookmark or something to push any local bookmark to new remote.

martinvonz#1278
@SoraTenshi
Copy link
Contributor

but using --remote as the override seems a little obscure to me.

Yes. That's why I added a hint saying "... Use --remote=origin to push to new remote."

My first guess would be that specifying the bookmark with -b was the way to do that.

That seemed scary. User might expect the bookmark would be pushed to the associated remote as git push would do.

As someone who just recently got around starting to use jj i can confirm it.
Bookmarks are in my brain associated with a branch and remote, so using a jj git push -b main looks a bit scary, and i even used it first only on a repo i don't really care about where i am the only user of.
So yeah, i can second the scary part of it :)

@martinvonz
Copy link
Owner

but using --remote as the override seems a little obscure to me.

Yes. That's why I added a hint saying "... Use --remote=origin to push to new remote."

I suppose we could have a separate flag instead, if people like that better. --allow-new-tracking or something.

@ilyagr
Copy link
Collaborator

ilyagr commented Oct 30, 2024

(No action needed)

The difference between jj git push in repo with one remote, jj git push in repo with multiple remotes, and jj git push --tracked is becoming a bit confusing.

I don't think it has to be fixed in this PR. Fixing this problem might be worth the added confusion until we figure out a better approach (and I don't have one clearly in mind).

I suppose we could have a separate flag instead, if people like that better. --allow-new-tracking or something.

I like this line of thinking, but I'm not sure what the flag should be exactly or how to name it. Should it allow new tracking for branches that are not already tracking something? Should it exist in addition to --tracked or should it replace it?

@yuja
Copy link
Collaborator Author

yuja commented Oct 31, 2024

We can of course add --allow-new-tracking (i.e. push local-only or tracking bookmarks by default) or --allow-new-bookmark (i.e. push tracking and --change bookmarks by default). Implementation-wise, the latter is simpler because we can remove the special case of @git tracking bookmarks, but I'm not sure if we want this level of strictness.

My feeling is that --remote=NAME is kinda okay as a flag to express user's intent to push new bookmarks to the specified remote.

@martinvonz
Copy link
Owner

My feeling is that --remote=NAME is kinda okay as a flag to express user's intent to push new bookmarks to the specified remote.

I would expect that --remote=NAME is just about restricting the set of remotes to the specified one. I think I would find it surprising if it changed the behavior in other ways.

@yuja
Copy link
Collaborator Author

yuja commented Nov 1, 2024

Are we okay to change jj git push to not push new bookmarks by default?

  • jj git push -b tracking updates tracking@origin
  • jj git push -b local-only fails
  • jj git push --new-bookmark -b local-only creates local-only@origin and tracks it
  • jj git push -c @- creates new push-xxx@origin and tracks it (--new-bookmark is implied for push-xxx)
  • jj git push --all pushes tracking bookmarks, warns skipped bookmarks (basically the same as --tracked)
  • jj git push --all --new-bookmark pushes all bookmarks

This behavior is easier to explain and implement than --allow-new-tracking.

@ilyagr
Copy link
Collaborator

ilyagr commented Nov 1, 2024

I like this idea in general, though I'd implement it after the release to give us a month to test it out and to see whether it confuses people. Either in this way or some other, I'd like more people to spend some time trying it out and/or thinking about how well it works for them.

One possibility is to have a --set option that acts as your --new-bookmarks and --create option that only creates remote bookmarks. The default behavior could be called --move. Then it's analogous to jj branch commands.


Update: It's less clear how branch deletion fits into my concept, and it breaks the analogy a bit on second thought. It could make sense to consider deletion a kind of moving (so --set and --move would allow it) for this. Or, we could have a binary option -- either --allow-deletion or --no-deletion -- for this.

If we don't go with --set/--create, I'm going back and forth on the question of whether it'd be weird for jj git push --all to allow deletion but not creation. It makes sense from a certain perspective, but could also be unexpected.

@ilyagr
Copy link
Collaborator

ilyagr commented Nov 1, 2024

jj git push --all pushes tracking bookmarks, warns skipped bookmarks (basically the same as --tracked)

It might then make sense to rename --all to --tracked. I'm not sure whether it's better to have --all and --tracked as we have now or --tracked and --tracked --new-bookmarks (with an implicit "or" in between).

This PR already has this problem: --all is no longer an all-or-nothing operation (which I think it is before this PR? Let me know if I'm confused about that). I am worried about people losing access to their work because they do jj git push --all on one computer and then, say, drive to work without noticing that a branch didn't get pushed. Perhaps we shouldn't call it --all in this case? (For -b, this PR avoids any problem by refusing to push anything and printing a red error)

I'm not sure how bad this problem is (this PR's jj git push --all does print a warning; will people be conditioned to read it or to ignore it?) or whether it should be blocking (especially since I don't have a good fix in mind, and pushing too much is also a potentially serious problem that this PR does address). So, I'm not sure what the best course of action is.

Update: One possible solution would be to have jj git push --all fail with a red error in this case and require the user to add a flag, either --new-branches or --no-new-branches. Not sure whether this is great UI or a great idea, but it'd avoid the issue I described, I think, either with the PR's current approach or with the other approaches discussed above.

@yuja
Copy link
Collaborator Author

yuja commented Nov 1, 2024

though I'd implement it after the release to give us a month to test it out and to see whether it confuses people.

Agreed.

Update: It's less clear how branch deletion fits into my concept,

Yep. I wouldn't want to think about the movement on jj git push. It's the command to synchronize local changes with the remote.

This PR already has this problem: --all is no longer an all-or-nothing operation (which I think it is before this PR? Let me know if I'm confused about that). I am worried about people losing access to their work because they do jj git push --all on one computer and then, say, drive to work without noticing that a branch didn't get pushed. Perhaps we shouldn't call it --all in this case? (For -b, this PR avoids any problem by refusing to push anything and printing a red error)

I assume the user would notice warnings about skipped bookmarks. If they don't, they wouldn't notice push error either.

I have no idea whether --all should imply --new-bookmark. In some sense, --all can be considered a flag to disable safety checks and push everything.

@ilyagr
Copy link
Collaborator

ilyagr commented Nov 2, 2024

I assume the user would notice warnings about skipped bookmarks. If they don't, they wouldn't notice push error either.

My reasoning is that people pay attention when nothing is pushed and all they see is an error. If people see the familiar progress bar of branches being pushed, they might not notice the warning or that the branch they cared about was not pushed.

So, I like --all being an all-or-nothing operation. All-or-nothing operations are easy to reason about. Partial success requires attention to understand. Sacrificing this property to fix another problem would be just that, a sacrifice.

Aside: I've considered from time to time also having a --all --push-what-you-can option, but people will hopefully feel like they should pay attention and understand the outcome when they use it. It should not be the default, it should be the command you do after --all fails and you are ready for things to go wrong.

Aside: I'm not sure --all is that great of a UI in the first place for pushing anywhere but a personal fork. But I'm not sure how to change it.

@yuja
Copy link
Collaborator Author

yuja commented Nov 2, 2024

Aside: I'm not sure --all is that great of a UI in the first place for pushing anywhere but a personal fork. But I'm not sure how to change it.

Maybe deprecate --all and suggest -b glob:* instead? It should match your intuition. --all would skip conflict bookmarks (so user might lose data), but -b glob:* wouldn't.

@ilyagr
Copy link
Collaborator

ilyagr commented Nov 2, 2024

That's an interesting thought. I don't understand your last point though: what would -b glob:* do for conflicted bookmarks?

@yuja
Copy link
Collaborator Author

yuja commented Nov 2, 2024

what would -b glob:* do for conflicted bookmarks?

push would fail at all (because the specified bookmarks couldn't be pushed.) OTOH, --all would emit warning and continue.

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

Successfully merging this pull request may close these issues.

5 participants