git-imerge icon indicating copy to clipboard operation
git-imerge copied to clipboard

Allow a rebase to be `finish`ed before it is done

Open mhagger opened this issue 8 years ago • 1 comments

I'm writing this up in a little more detail because @waldyrious asked about it.

It would be nice to allow an in-progress rebase to be simplified to "lock in" the progress that has been made so far, even if the imerge is not finished. Basically, the program should find the rightmost vertical column of completed merges, and should use that column as the final value of the branch. The net result would be that the branch has been rebased not all the way to the tip of the other branch, but rather to some earlier commit on that branch.

For example, consider the following merge diagram for a git imerge rebase of branch onto master. The user has already resolved some conflicts, but there are more blockers that the user hasn't resolved yet:

o - 0 - 1  - 2  - 3  - 4  - 5  - 6  - 7  - 8  - 9  - 10  - 11    ← master
    |                            |    |    |    |    |     |
    A                            A6 - A7 - A8 - A9 - A10 - A11
    |                            |    |
    B                            B6 - B7   #
    |                            |
    C - C1 - C2 - C3 - C4 - C5 - C6   #
    |             |              |
    D             D3             D6
    |             |              |
    E - E1 - E2 - E3 - E4 - E5 - E6

    ↑
  branch

The user might decide to give up. Instead of throwing away all of the work, we could offer a command like git imerge finish --partial, which, noticing that the rightmost complete vertical column is 6 - A6 - B6 - C6 - D6 - E6, would rebase branch to 6:

o - 0 - 1  - 2  - 3  - 4  - 5  - 6  - 7  - 8  - 9  - 10  - 11    ← master
                                 |
                                 A6
                                 |
                                 B6
                                 |
                                 C6
                                 |
                                 D6
                                 |
                                 E6

                                 ↑
                               branch

I think this shouldn't be too difficult to implement. To find the rightmost complete column, one could use code like that in MergeFrontier.map_known_frontier() to ask the MergeState which merges are known, like

(i1, i2) in block and not block.is_blocked(i1, i2)

To perform the simplification, one would do something very much like MergeState.simplify_to_rebase(). In fact, I think if i1 were an optional parameter to this method, it would already do the right thing; i.e., replace the start of this function with:

def simplify_to_rebase(self, refname, i1=None, force=False):
    if i1 is None:
        i1 = self.len1 - 1

The only deeper issue is that it might be that partially-completed rebases sometimes look more like

o - 0 - 1  - 2  - 3  - 4  - 5  - 6  - 7  - 8  - 9  - 10  - 11    ← master
    |                            |
    A                            A6
    |                            |
    B                            B6
    |                            |
    C - C1 - C2 - C3 - C4 - C5 - C6
    |             |
    D             D3
    |             |
    E - E1 - E2 - E3

    ↑
  branch

In this case, even though column 3 is probably all mergeable, we don't actually have those merges available. In this situation, git imerge finish --partial could

  1. Just refuse to do anything (or rebase to an earlier complete column, if available).
  2. Try to create those merges on the fly, which should usually (but not always) be possible without conflicts.

But long-term, I think it would make sense to use a different filling strategy for rebases that always fills complete columns before proceeding towards the right, because this strategy would mean that we could avoid big horizontal lines of merges, which I think would speed up the typical rebase overall. If we were using this strategy, then the above situation should never arise.

mhagger avatar Jul 10 '16 08:07 mhagger

This is a much needed feature. I wasted a lot of time rebasing things over from scratch after messing the rebase in the middle.

I also realized that if the rebased branch has tags, I need to preserve that history for reproducibility. Not sure if it possible to split the branch this way. Just looking at the graphs.

abitrolly avatar Jul 14 '20 11:07 abitrolly