On Tue, Sep 7, 2021 at 11:51 AM Johannes Schindelin <Johannes.Schindelin@xxxxxx> wrote: > > Hi Hannes, > > On Thu, 2 Sep 2021, Johannes Sixt wrote: > > > Am 02.09.21 um 16:18 schrieb Johannes Schindelin: > > > On Wed, 1 Sep 2021, Junio C Hamano wrote: > > >> A good goal. There is no remaining use case where (a fictitious and > > >> properly working version of) "--preserve-merges" option cannot be > > >> replaced by "--rebase-merges", is it? I somehow had a feeling that > > >> the other Johannes (sorry if it weren't you, j6t) had cases that the > > >> former worked better, but perhaps I am mis-remembering things. > > > > > > I think that I managed to address whatever concerns there were about the > > > `--rebase-merges` backend in the meantime. > > > > That was either my suggestion/desire to make no-rebase-cousins the > > default. That has been settled. > > > > Or my wish not to redo the merge, but to replay the first-parent > > difference. The idea never got traction, and I've long since abandoned > > my implementation of it. > > Thank you for clarifying. > > Yes, I remember how that idea came up, and I even tried that strategy for > a couple of merging rebases of Git for Windows' branch thicket. Sadly, it > did not work half as well as I had hoped. > > The best idea I had back then still is in want of being implemented: sort > of a "four-way merge". It is basically the same as a three-way merge, but > allows for the pre-images to differ in the context (and yes, this cannot > be represented using the current conflict markers). Definitely not > trivial. merge-ort opens a new possibility (since it does merges without touching the index or working tree): Take the merge commit, M, that you are trying to transplant. Hold on to it for a minute. Do what rebase-merges does now; namely, do a simple merge of the desired new branches that otherwise ignores M to get your new merge commit N. Hang on to N too for a minute. Now use merge-ort to auto-remerge M (much like AUTO_MERGE or --remerge-diff does) to get a new merge commit that we'll call pre-M. If M was a clean merge that the user didn't amend, then pre-M will match M. If M wasn't a clean merge or was amended, then pre-M will otherwise differ from M by not including any manual changes the user made when they originally created M -- such as removing conflict markers, fixing semantic conflicts, evil changes, etc. Now we've got three merge commits: pre-M, M, and N. (Technically, pre-M and N might be toplevel trees rather than full commits, but whatever.) The difference between pre-M and M represent the manual work the user did in order to create M. Now, do a three-way (non-recursive) merge of those commits, to get the rebased result, R. This operation has the affect of applying the changes from pre-M to M on top of N. There's obviously some edge cases (e.g. nested conflict markers), but I think they're better than the edge cases presented by the alternatives: * the first-parent difference idea silently discards intermediate changes from reapplying other patches (especially if other patches are added or dropped), which to me feels _very_ dangerous * the current rebase-merges idea silently discards manual user changes within the original merge commit (i.e. it hopes that there is no difference between pre-M and M), which can also be lossy * I don't think this idea drops any data, but it does run the risk of conflicts that are difficult to understand. But I suspect less so than your five-way merge would entail. If the difficulty of conflicts in this scheme is too high, we could do a few things like providing multiple versions (e.g. if either pre-M:file or N:file had conflicts, or maybe if R:file has nested conflicts, then place both R:file and N:file in the working tree somewhere) or pointing at special commands that help users figure out what went on (e.g. 'git log -1 --remerge-diff M -- file').