gitrebase

git rebase --rebase-merges not preserving merge order


I have a repo that looks like this...

-+----*----*------*-------------------------  Main
  \------------+---------+------+-- Dev
   \-*--*--*--/-*--*--*-/-*--*-/  Feature1

That's my best attempt at ASCII art anyway. I'm actually using gitgraph in VS Code to visualize my repo.

The *s represent commits and the slashes are merges. So basically I started a Dev branch off of my Main branch. Then from Dev, I started a Branch called Feature1 (for the purposes of this example anyway). After several commits, I merged Feature1 onto Dev, but kept adding commits to Feature1 and merging to Dev. Also there were other commits merged into Main during this time.

Now I want to rebase Dev onto Main. So I issue the command git rebase MAIN --rebase-merges. What I expect is something like this

  --*--*--*-+------------+---------+------+-- Main
             \-*--*--*--/-*--*--*-/-*--*-/  

What I get is more like this

  -*--*--*-+-----------------------------+--+--+
            \--------------------*--*---/--/--/
             \----------*--*--*--------/--/
              \--*--*-*---------------/

I've tried passing -i to the rebase and editing the todo script. It has all the merges at the end. Then I tried moving them where they should logically go, but I end up with just a flat line with no merge history at all.

Any idea what I'm doing wrong? I Googled for documentation of the todo script because there are reset commands in there too that I don't know what they do or how they interact with the merge command. But there was too much noise in the Google results. And a lot of old results recommending a command line option that was removed years ago.

Would this have worked better if my Dev branch had looked like this instead?

  \------------+-----------+------+-- Dev
   \-*--*--*--/\--*--*--*-/\-*--*-/  Feature1

Solution

  • I seem to have stumbled upon the magic incantation to use in the todo file when doing git rebase main -i --rebase-merges

    As I said, it put all of the merge commands at the end of the script. I edited it so that it looked like:

    # Branch branch-name-1
    label branch-point-1
    pick 123456789 description
    pick 897312987 description
    label branch-name-1
    reset branch-point-1
    merge -C 098234589 branch-name-1 # Merge pull request #123 from branch-name
    
    # Branch branch-name-2
    label branch-point-2
    pick 09845abce description
    pick 987dicabe description
    label branch-name-2
    reset branch-point-2
    merge -C 903478028 branch-name-2 # Merge pull request #123 from branch-name
    
    # etc
    

    Each section had a reset command after the comment and before the first pick. I replaced that with a label. The name for the label is unimportant but must be unique and is what you use on the reset command just before the merge. I copied the merge commands from where they were at the end of the script so that I didn't have to worry about hash was.

    The resulting graph isn't exactly what it was before, but it's as close as I could get and much cleaner than the overlapping thing it was giving me before.