-
Notifications
You must be signed in to change notification settings - Fork 379
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: Support jj fix -r X
to fix X
with minimal effects on X..
#3805
Comments
I don't really understand the FR as written. Is it not essentially proposing rebasing the descendant commits instead of fixing them? Can you provide a specification of the behavior not in terms of the current implementation?
Rebasing instead of fixing or reparenting descendants becomes important/useful if the fixes are expensive to compute (just opened #3808 in relation). It's annoying when I have to wait for |
IMO, We should always reparent instead of rebasing (to avoid conflicts), but we should do so while solving the problem that @arxanas mentioned. def fix(revisions):
fixes_required = {rev: changed_files(rev) for rev in revisions}
for rev in revisions:
new_files = rev.files
for file in changed_files(rev):
if file in fixes_required:
file.set_content(run_fix_command(file.path))
else:
# There was originally no change, but the fix command changed our parent
file.set_content(rev.parent.files[file.path])
reparent_children(rev) Suppose that commit
|
Unfortunately, this approach doesn't solve the problem I have. It supposes that a fix can be run on individual files, but (as far as I can tell) The file-level-granularity "redoing" approach you suggest makes sense for many other classes of formatter-style fix. It's also similar to an approach I recall at a previous company where people did automatic codebase-wide refactorings and opted to drop changes in conflicting files altogether, although the redoing would be done manually at a later time. |
Why is there a |
@joyously It needs to operate on and modify the commit graph. How could it exist without the version control system? It might be best to start a separate discussion regarding the suitability/scope of the |
This discussion seems to be about code formatting. That would be a normal change in files, not anything to do with the commit graph. |
It’s for applying tools like formatters to a range of commits in batch. |
By design, fix is not suitable for all use cases - like you said, fix is designed to run formatters which take only a single file as input. Your use case is reasonable, but it should be solved by |
I still don't see why a VCS would have a command that is for affecting the content in batch when that changes history. If it's for doing a batch |
@joyously I'm not sure what the problem is with changing history, though maybe I'm misunderstanding your point. Literally everything in
My use case is:
If I were to not use
It's a massive pain in the ass, and still ends up rewriting history, so I'm confused about your opposition to Also, how do you feel about |
@matts1 Your use case can be solved other ways: simply run your formatter and squash that into whatever revision you want (or leave as a separate commit with its own message since it is a separate change). I guess my opposition comes from a viewpoint of the VCS being invoked only when the code is ready to share, and that the historical states are those already shared. I just don't see why a VCS has anything to do with batch processing of file contents. |
I contest the design and argue that
One would hope so, but I've found that it doesn't work that well in practice due to meaningless conflicts:
Generally speaking, there are two cohorts of VCS user when it comes to this kind of thing:
@joyously I'm happy to discuss more but I think we should move to a separate discussion of the general suitability of |
I did not follow this discussion closely but can you explain what the semantic difference here should be? I heavily agree with @matts1 that this functionality is covered by |
@joyously My take is that The reason there's nothing wrong with rewriting history is that if rewriting history for a commit was truly bad, then it should go into your immutable heads. For example, if you, for whatever reason, didn't want to support amending a commit that had been sent to github for review, just put FWIW, I think this may also be related to the code review system people use. Your principles you mention are probably a very good set of principles for working with a code review system where you review PRs, and especially so if they don't allow rewriting history. However, rewriting history is the recommended approach for both gerrit and piper, because both of these systems have you review individual commits, where each commit has a stable change-id. So I can send out commits A and B, get a review requesting changes on A, I do agree with @arxanas that there are definitely two classes of VCS users. During the development process, I'll be doing rebases, amends, octopus merges, squashes, editing intermediate commits, etc. After code review, I continue doing all that, rewriting history on existing commits already sent for review. I only stop rewriting history once a piece of code has been submitted. I think the metrics we should be marking against are:
|
I think what bothers me about a
|
I haven't followed the whole discussion, but I wonder whether this could be addressed by some version of Conceptually (and perhaps for real), I wonder if the version of |
I don't have any particular qualms with the name, but I wouldn't be opposed to renaming it to something like
It does not (and it shouldn't, considering the use case). This isn't for arbitrary tools, but specifically for formatters.
I don't see how this is any different from any other command that affects multiple revisions (eg. rebase). And the boundary on immutable is simply that jj won't let you edit an immutable commit. That being said, re "how would you know if you affected something you didn't intend to", the only time it should ever be a problem to change history by running a formatter on a change and changing history is if that commit should not be changed at all, and those commits should just be marked as immutable. If I accidentally ran a formatter on a commit I didn't intend to, my code looks prettier but still runs the same. As proof of my earlier statement:
The whole file - formatters generally work on a file level. I don't think there's anything wrong with this. If I ran
I'm no expert on this, but I'd imagine once before the command is run, and once after the command completes. I don't see how it's any different from any other command that rewrites history (eg.
This is an extremely common use case, and to the best of my knowledge, there's no easy way to achieve it.
I strongly disagree with this one. While I do like the exisence of
|
I am not suggesting this should be the default behavior. We can also leave it at "conceptually" and not do it in practice at all. My main point is that we can think of this command as doing two relatively orthogonal things. We can think separately about the options for how to "fix" the commit, and for options of how to then squash or integrate the new patch into the commit graph. This also suggests to me that solving this in parallel to
I can think of a few possible things: squash normally, squash with It bothers me a little (unrelated to your comment) that whether or not using
This is true, I'm perhaps polluting this discussion by thinking about |
I do agree with two of those three use cases. I don't currently like that only the first option is currently supported - I personally like the idea of a With all that said, I'd much prefer |
I may have misunderstood what this issue is about. My first guess at what the
Yes, I never meant the user to be forced to squash things manually. If we implemented manual squashing at all, the users would have to opt into it. |
@hooper What was your intention here? I had assumed that we would never want to rebase when we run |
Yes, I think this was my confusion. I assumed that In reality (as I'm sure most people reading are well aware), It is true that "reparenting" behavior seems generally more useful for a I'm unsure what's best. I think reparenting by default might be reasonable, but it has the problem that it's confusingly different from how all other |
It occurs to me that this sounds an awful lot like a pre-commit hook. |
It does have similarities, but pre-commit hooks don't make sense in So the workflow for most users will probably be:
|
Problem:
Some users find that
hg fix -s X
formats more files/lines than they wanted to be formatted inX..
.Solution:
If the user specifies
-r X
instead of-s X
, don't include the diffs ofX..
in the files/lines to be fixed. The details will depend a lot on how we implement line ranges. As for the set of files to be fixed, it basically means we would skip theparent_tree.diff_stream()
section ofjj fix
when pickingToolInput
s forX..
.Alternatives:
We fix files in
X..
, instead of rebasing them, to avoid merge conflicts between the user's changes and the code formatter's changes. I consider rebasing to be a worse alternative, because those conflicts are both confusing to deal with (especially if a diff tool ignores whitespace changes) and not very useful. Rebasing is potentially faster than some code formatters, but not enough to justify exposing users to unnecessary conflicts.Context:
Anecdotally, Google has had many users of
hg fix
over many years, and they don't ask for the rebasing behavior. They do occasionally ask for something like this FR.The text was updated successfully, but these errors were encountered: