Search code examples
gitversion-control

Relocate git branch into another branch


Assuming:

  • C = Commit
  • B-Name = Branch-Name
  • R = Rebase

Currently I have a branch like this:

--(C1)                    :B-Master
     \--(C2)--(C3)        :B-Feature1
     \--(C4)--(C5)        :B-Feature2
     \--(C6)--(C7)        :B-Feature3

How do I rebase into something like this:

---(C1)-------------(R1)----------------(R2)            :B-Master
     \--(C2)--(C3)--/ \                /                :B-Feature1
                       \--(C4)--(C5)--/                 :B-Feature2
     \--(C6)--(C7)                                      :B-Feature3

Explanation:

Currently in my Master branch there's a last commit of C1. And at C1 I have multiple different idea coming regarding different feature. I start to code each of them on different branch. When each of the feature completed.

Example: When Feature1 branch complete, I want to rebase the Feature2 branch into R1. Meaning the Feature2 branch has all code of Feature1 code before C4 even exist.


Solution

  • Existing commit C4 cannot be changed in any way at all and that includes the fact that its parent is commit C1. So you can't get what you want, but you can probably get what you need (as the Rolling Stones song goes): a new C4' (C8?) that is a lot like C4 but attaches to R1.

    I prefer single-letter names for commits, and would draw the original this way:

    ...--B   <-- master
         |\
         | C--D   <-- feature1
         |\
         | E--F   <-- feature2
          \
           G--H   <-- feature3
    

    We'll end up with, e.g.:

    ...--B------I------J   <-- master
         |\    / \    /
         | C--D   E'-F'   <-- feature2
          \    `......    <-- feature1
           G--H           <-- feature3
    

    where commit I is a (forced) merge commit made to merge feature1 into master without doing a fast-forward, E'-F' are the copies of E-F altered to come after I, J is another forced merge, and G-H are untouched as they still spring from commit B:

    git switch master
    git merge --no-ff feature1
    git switch feature2
    git rebase master
    git switch master
    git merge --no-ff feature2
    

    If you don't need to force merge commits I and J to exist, see Bogdan Onischenko's answer.