jj icon indicating copy to clipboard operation
jj copied to clipboard

conflicts: add labels to conflicts

Open scott2000 opened this issue 1 month ago • 4 comments

Resolves #1176. I'm not sure if this is the best solution, but I wanted to try it out and see how it feels. This could probably be split into smaller PRs if we decide we want to follow this approach. These are the steps I took:

  1. Remove MergedTreeId::Legacy variant, since it complicated implementation and I believe it is unnecessary now.
  2. Add conflict labels to MergedTree and MergedTreeId (as suggested by @martinvonz)
  3. Store labels in simple backend, local working copy, and git backend
  4. Materialize labels in conflict markers if present
  5. Add labels to merge conflicts
  6. Add labels to rebase conflicts
  7. Add labels to squash conflicts

Many other places still do not add labels (e.g. jj split, jj absorb), so they would have to be added later.

Example conflict markers for merge with rtsqusxu and ysrnknol as parents:

<<<<<<< conflict 1 of 1
%%%%%%% rtsqusxu 2768b0b9 compared with vpxusssl 38d49363
-base
+left
+++++++ ysrnknol 7a20f389
right
>>>>>>> conflict 1 of 1 ends

Example conflict markers for rebase of ysrnknol onto rtsqusxu:

<<<<<<< conflict 1 of 1
%%%%%%% rebase destination (rtsqusxu 2768b0b9) compared with parents of srnknol 7a20f389
-base
+left
+++++++ rebased commit (srnknol 7a20f389)
right
>>>>>>> conflict 1 of 1 ends

Example conflict markers for squash of ysrnknol into rtsqusxu:

<<<<<<< conflict 1 of 1
+++++++ squash destination (rtsqusxu 2768b0b9)
updated in destination
%%%%%%% squashed commit (ysrnknol 7a20f389) compared with parents of ysrnknol 7a20f389
-base
+squashed
>>>>>>> conflict 1 of 1 ends

Checklist

If applicable:

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

scott2000 avatar Oct 10 '25 13:10 scott2000

Note that this PR seems to implement it a bit differently than what I suggested on #1176 . My suggestion there was to record a label associated with each diff in the conflict, not with each term. I don't know which is better, and I haven't reviewed the code yet (only at a high enough level to notice that). One advantage of attaching a label to a diff is that it can also make sense when the involved trees don't come directly from commits.

martinvonz avatar Oct 11 '25 17:10 martinvonz

Note that this PR seems to implement it a bit differently than what I suggested on #1176 . My suggestion there was to record a label associated with each diff in the conflict, not with each term. I don't know which is better, and I haven't reviewed the code yet (only at a high enough level to notice that).

Oh yeah, I may have misunderstood. I think I was implementing it based on a Discord conversation we had a few weeks ago. I think it may actually be better to record labels per term rather than per diff because it seems to me like it would work better with the current simplification logic. Sometimes simplifying conflicts causes two diffs to be combined into a single diff, and it might be difficult to combine the labels when this happens.

For instance, if you rebase a commit with parent A onto commit B, it might get a conflict label indicating "diff from A to B". If you then rebase it from commit B to commit C, I think ideally the label should indicate "diff from A to C". With term labels, this happens automatically, since the two terms with label "B" are discarded when simplifying. With diff labels, I think we'd either need some non-trivial logic to merge labels, or we'd need to settle for something like "diff from A to B, then diff from B to C".

One advantage of attaching a label to a diff is that it can also make sense when the involved trees don't come directly from commits.

I think we can still get this to work with term labels. For instance, I'm thinking we could do something like this for conflicts resulting from interactive squash:

<<<<<<< conflict 1 of 1
+++++++ squash destination (rtsqusxu 2768b0b9)
left
%%%%%%% squashed commit (selected changes from ysrnknol 7a20f389) compared with parents of ysrnknol 7a20f389
-base
+right
>>>>>>> conflict 1 of 1 ends

It might still be tricky though for cases where jj squash combines multiple commits, or for commands that construct temporary commits which aren't normally visible to the user, so I'm not totally sure though.

scott2000 avatar Oct 11 '25 18:10 scott2000

Also I suggest that if bookmarks are used they show optionally, names are more descriptive than numbers.

mamcx avatar Oct 29 '25 15:10 mamcx

Also I suggest that if bookmarks are used they show optionally, names are more descriptive than numbers.

Yeah, that would definitely be nice. I'm thinking it would be a follow-up to this PR since it would require some additional changes to pass down the required information.

scott2000 avatar Oct 30 '25 00:10 scott2000