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: Command for resolving divergent commits #2796

Open
martinvonz opened this issue Jan 9, 2024 · 4 comments
Open

FR: Command for resolving divergent commits #2796

martinvonz opened this issue Jan 9, 2024 · 4 comments
Labels
enhancement New feature or request

Comments

@martinvonz
Copy link
Owner

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

When there are divergent commits, the user currently has to inspect the commits' descriptions and contents and then decide what to do (typically abandon one of the commits).

Describe the solution you'd like

We should be able to automate the resolution in most cases. The description has usually changed on at most one side. Same thing with other metadata (user/committer name). We should be able to to walk predecessors to find a common ancestor (in most cases). The resolved content should probably be calculated by applying the interdiff between the common ancestor and one divergent commit into the other divergent commit.

@PhilipMetzger PhilipMetzger added the enhancement New feature or request label Jan 9, 2024
@ilyagr
Copy link
Collaborator

ilyagr commented Jan 10, 2024

Nice idea!

I think you are suggesting a regular 3-way merge of the two divergent commits, the only difference being is that we merge the metadata of the commits in addition to the commit contents.

I couldn't immediately come up with an example where this would do something obviously bad.

One question is what we do if the two commits don't merge perfectly. I suppose we could have several iterations:

  • do nothing if the conflicts between divergent commits don't resolve perfectly
  • merge what we can and create simplified divergent commits
  • introduce a "conflicted commit" AKA Merge<Commit> type and present conflicted commits to the user somehow

Finally, this reminds me of the idea to make all conflict resolution and simplification reversible, so that if you don't like the way jj simplified some conflict, you could get a less simplified state and then do your own resolution some other way.

@martinvonz
Copy link
Owner Author

(Sorry about the slow response. I forgot about this message for a while and noticed it in my mail backlog now.)

I think you are suggesting a regular 3-way merge of the two divergent commits,

No, let me give an example. Let's say you started with a linear chain of commits A, B, C. One side of the divergence then modified C somehow, while the other side rebased C onto A. You would then have something like this:

C2 divergent
|
| C hidden
|/
B
|
| C1 divergent
|/
A

My proposal is to apply the interdiff between C and C1 into C2 or the other way around. In the scenario above, it's clearly better to apply the interdiff between C and C2 into C1, since that wouldn't undo the rebase operation. But let's say we applied the interdiff between C and C1 into C2. The interdiff is then calculated as if C had been rebased to C1's parents and then diffing the result against C1, i.e. (A (C-B))-C1. Of course, if C1 was created by just jj rebase, then the interdiff would be empty.

One question is what we do if the two commits don't merge perfectly.

If the content doesn't merge perfectly, it seems pretty clear to me that we should record that a conflict in the resulting commit as we normally do, so I suppose you're talking about conflicts in the descriptions/metadata here. One option is to let command for resolving divergence be interactive, so we could ask the user to resolve the conflict in the description before continuing.

@ilyagr
Copy link
Collaborator

ilyagr commented Jan 22, 2024

I see, that's a very nice example.

I still have a couple of concerns, though I'm not sure how important they are:

I don't like that we're making the choice for the user of whether the outcome of the operation will be C2 or a modified version of C1. We could ask the user, I suppose, but it might end up being a confusing question.

, it seems pretty clear to me that we should record that a conflict in the resulting commit as we normally do

In theory, this sounds fine. In practice, I think the user will often (usually?) want to pick one of the two sides. (At least, for me, divergence is usually when an editor saved some weird version of a file at the same time as I was doing jj new somewhere_else). The experience of doing this in jj is currently not great, you either have to open meld, or edit the files manually. There is not even a good way to know which side of the conflict comes from where.

The fact that the resolution you suggested would be done by an explicit, undo-able command helps here. Also, hopefully, we'll improve this experience (Discord discussion).

One option is to let command for resolving divergence be interactive, so we could ask the user to resolve the conflict in the description before continuing.

Sounds reasonable.

This is outside the scope of this PR, but I still vaguely wish that we could postpone resolving such conflicts, like file conflicts. Perhaps we could have a notion of a commit with WIP description (or WIP metadata, including tags) that would apply in this situation, but also when commits are split or squashed.

@isovector
Copy link

If there were a revset that targeted divergent commits, it seems like this could be done on the user's side via git abandon -r (divergent_commits() & ~working_tree_changes)

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

4 participants