Search code examples
gitgitlab

pushing stacked git branches back into main


I've been trying to learn how to successfully create branch B off branch A, where both branches are local branches to me, and merge them into my company's code in GitLab. I've encountered a lot of interesting reading, but I'm still confused about how to best apply my branches back to main.

Right now we have:

main ->
  branch_A ->
    branch_B

Say that I finish branch A and merge my MR. At this point main will have the code from branch A (as a merge commit I believe), and branch B will have the code from branch A as the original commits.

I'm confused about how to finish my branch B MR, because I think there will be conflicts due to the branch A code being in both places. How can I get my branch B commits into main as well? This is on GitLab.

(If I try to rebase branch B onto main at this point, I think I would still see the same conflicts, but I would simply encounter them as part of the rebase. My goal is to somehow get my code into main without seeing a bunch of bogus conflicts.)

(For a while I thought that this excellent question would help me. However that is more about how to get changes from main into chained branches. My question is basically the reverse, how to get the code from the branches back into main as part of my MRs when I'm done. If I had followed that other question's instructions I guess that both MRs could be fast-forwarded. However I think that GitLab may not do a fast-forward.)


Solution

  • Tl;dr: After having merged branch A, you merge branch B. Done.

    You started with this history:

    --o--o                 <-- main
          \
           o--o--o         <-- branch A
                  \
                   o--o    <-- branch B
    

    Then you merged branch A. Assuming that Gitlab does not do fast-forward merges, you got this history:

    --o--o---------MA      <-- main
          \       /
           o--o--o         <-- branch A
                  \
                   o--o    <-- branch B
    

    At this point, the most natural thing to do is to merge branch B. Now you get this history:

    --o--o---------MA-----MB  <-- main
          \       /      /
           o--o--o      /     <-- branch A
                  \    /
                   o--o       <-- branch B
    

    In this merge, the commits on branch A will not cause any conflicts. The power of the commit graph is at work here: A three-way merge of commit MA and branch B is performed. The merge base is the tip of branch A. But since there is no content difference between the merge base (branch A) and MA, no conflicts can occur.

    Others have suggested that you rebase branch B onto main instead. You can do that if you wish:

    git rebase main branch_B
    

    You get this history:

    --o--o---------MA        <-- main
          \       / \
           o--o--o   \       <-- branch A
                      \
                       o--o  <-- branch B
    

    During this operation, the commits on branch A will not cause any conflicts, either.

    Now you can merge the rebased branch into main as well:

    --o--o---------MA---------MB  <-- main
          \       / \        /
           o--o--o   \      /     <-- branch A
                      \    /
                       o--o       <-- branch B
    

    It is a matter of personal taste or of convention how your team operates whether you rebase branch B or not. It is absolutely not necessary to do so.