Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
From: Sergey Organov <hidden>
Date: 2018-02-28 05:44:22
Hi Johannes, Johannes Schindelin [off-list ref] writes:
Hi Buga, thank you for making this a lot more understandable to this thick developer. On Tue, 27 Feb 2018, Igor Djordjevic wrote:quoted
On 27/02/2018 19:55, Igor Djordjevic wrote:quoted
It would be more along the lines of "(1) rebase old merge commit parents, (2) generate separate diff between old merge commit and each of its parents, (3) apply each diff to their corresponding newly rebased parent respectively (as a temporary commit, one per rebased parent), (4) merge these temporary commits to generate 'rebased' merge commit, (5) drop temporary commits, recording their parents as parents of 'rebased' merge commit (instead of dropped temporary commits)". Implementation wise, steps (2) and (3) could also be done by simply copying old merge commit _snapshot_ on top of each of its parents as a temporary, non-merge commit, then rebasing (cherry-picking) these temporary commits on top of their rebased parent commits to produce rebased temporary commits (to be merged for generating 'rebased' merge commit in step (4)).For those still tagging along (and still confused), here are some diagrams (following what Sergey originally described). Note that actual implementation might be even simpler, but I believe it`s a bit easier to understand like this, using some "temporary" commits approach. Here`s our starting position: (0) ---X1---o---o---o---o---o---X2 (master) |\ | A1---A2---A3 | \ | M (topic) | / \-B1---B2---B3 Now, we want to rebase merge commit M from X1 onto X2. First, rebase merge commit parents as usual: (1) ---X1---o---o---o---o---o---X2 |\ |\ | A1---A2---A3 | A1'--A2'--A3' | \ | | M | | / | \-B1---B2---B3 \-B1'--B2'--B3' That was commonly understandable part.Good. Let's assume that I want to do this interactively (because let's face it, rebase is boring unless we shake up things a little). And let's assume that A1 is my only change to the README, and that I realized that it was incorrect and I do not want the world to see it, so I drop A1'. Let's see how things go from here:quoted
Now, for "rebasing" the merge commit (keeping possible amendments), we do some extra work. First, we make two temporary commits on top of old merge parents, by using exact tree (snapshot) of commit M: (2) ---X1---o---o---o---o---o---X2 |\ |\ | A1---A2---A3---U1 | A1'--A2'--A3' | \ | | M | | / | \-B1---B2---B3---U2 \-B1'--B2'--B3'Okay, everything would still be the same except that I still have dropped A1'.quoted
So here, in terms of _snapshots_ (trees, not diffs), U1 = U2 = M. Now, we rebase these temporary commits, too: (3) ---X1---o---o---o---o---o---X2 |\ |\ | A1---A2---A3---U1 | A1'--A2'--A3'--U1' | \ | | M | | / | \-B1---B2---B3---U2 \-B1'--B2'--B3'--U2'I still want to drop A1 in this rebase, so A1' is still missing. And now it starts to get interesting. The diff between A3 and U1 does not touch the README, of course, as I said that only A1 changed the README. But the diff between B3 and U2 does change the README, thanks to M containing A1 change. Therefore, the diff between B3' and U2' will also have this change to the README. That change that I wanted to drop.quoted
As a next step, we merge these temporary commits to produce our "rebased" merged commit M: (4) ---X1---o---o---o---o---o---X2 |\ |\ | A1---A2---A3---U1 | A1'--A2'--A3'--U1' | \ | \ | M | M' | / | / \-B1---B2---B3---U2 \-B1'--B2'--B3'--U2'And here, thanks to B3'..U2' changing the README, M' will also have that change that I wanted to see dropped. Note that A1' is still dropped in my example.quoted
Finally, we drop temporary commits, and record rebased commits A3' and B3' as our "rebased" merge commit parents instead (merge commit M' keeps its same tree/snapshot state, just gets parents replaced): (5) ---X1---o---o---o---o---o---X2 |\ |\ | A1---A2---A3---U1 | A1'--A2'--A3' | \ | \ | M | M' | / | / \-B1---B2---B3---U2 \-B1'--B2'--B3'Now, thanks to U2' being dropped (and A1' *still* being dropped), the change in the README that is still in M' is really only in M'. No other rebased commit has it. That makes it look as if M' introduced this change in addition to the changes that were merged between the merge parents.
Except that original proposal suggests to cosider this a conflict and to stop for amendment, as U1' and U2' now differ. -- Sergey