Search code examples
gitgit-branchrebasegit-rewrite-historytree-conflict

How to make two git branches (with common history) coherent with each other after rebasing one of them?


I think that my title is not clear enough, so I will describe the problem:

In my git project, I have 3 branches: master, b1, and b2. Here is the history tree:

 A---B---C  master
          \
           D---E---F  b1
                    \
                     G---H---I  b2

Suppose I want to rebase the b1 branch and edit the E commit. After rebasing, commits E and F will be replaced by new commits E' and F' which have different commit SHAs. Therefore, the history in b1 will be different from history in b2:

 A---B---C  master
           \
             D---E'---F'  b1
                     
 A---B---C---D---E---F---G---H---I  b2

So my question is: how to make sure that b2 follows b1 (automatically gets the same new commits as b1) after rebasing b1 so that their respective histories stay coherent.


Solution

  • After your first rebase, it's not this:

     A---B---C  master
               \
                 D---E'---F'  b1
                         
     A---B---C---D---E---F---G---H---I  b2
    

    but rather this:

    A---B---C  master
             \
              D---Ea---F'  b1
               \      
                E---F---G---H---I  b2
    

    Here, Ea means the amended E commit. And you want this, if I understand correctly:

    A---B---C  master
             \
              D---Ea---F'  b1
                        \      
                         G'---H'---I'  b2
    

    You can achieve this using an interactive rebase:

    git checkout b2
    git rebase -i b1
    

    In the rebase edit you comment out the lines for commit E:

    # pick df8efe6 E
    pick a7fcbed G
    pick 936b51a H
    pick c77ca69 I
    
    # ...
    # Commands:
    # p, pick = use commit
    # ...
    # If you remove a line here THAT COMMIT WILL BE LOST.
    

    Responding to your comment, if you want to go all the way from the starting position (ABCDEFGHI) to the desired end positon:

    git checkout b2
    git rebase -i master
    

    In the editor:

    pick 1234567 D
    edit a7fcbed E
    pick 936b51a F
    pick c77ca69 G
    pick 1e8d614 H
    pick 8daafa7 I
    
    # ...
    # p, pick = use commit
    # e, edit = use commit, but stop for amending
    # ...
    

    When done, correct the b1 branch:

    git checkout b1
    git reset --hard 936b51a
    

    You can also look at the other answers for inspiration. I'm not sure why you want to achieve all of this in a single command; you still have to amend commit E somewhere in the process. It saves you one interactive rebase to do it this way.