Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges
From: Elijah Newren <hidden>
Date: 2021-09-07 22:48:36
On Tue, Sep 7, 2021 at 11:51 AM Johannes Schindelin [off-list ref] wrote:
Hi Hannes, On Thu, 2 Sep 2021, Johannes Sixt wrote:quoted
Am 02.09.21 um 16:18 schrieb Johannes Schindelin:quoted
On Wed, 1 Sep 2021, Junio C Hamano wrote:quoted
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').