Rebasing to remove parallel history and create a single linear history

130 views Asked by At

I created a feature branch from master branch. After that there is a commit [F1] from feature branch.

        [F1]            -- Feature Branch
       /
[M1]-[M2]               -- Master Branch

After that, feature branch is merged in master branch, and there are two more commits [M3] and [M4] in master branch.

        ----[F1]                   -- Feature Branch
       /        \
[M1]-[M2]-[M3]-[F1]-[M4]-[M5]       -- Master Branch

But now I would like to rebase to to create a single linear history.

[M1]-[M2]-[M3]-[F1]-[M4]-[M5]       -- Master Branch

Is that posible an how would I do it?

2

There are 2 answers

0
matt On BEST ANSWER

Your diagram is impossible:

        ----[F1]                   -- Feature Branch
       /        \
[M1]-[M2]-[M3]-[F1]-[M4]-[M5]       -- Master Branch

In the diagram, the same commit, F1, appears in two different places. That cannot be. I will assume that the second F1 is actually a true merge commit, and that what you have is this:

         -- F1 --
       /          \
M1 -- M2 -- M3 -- [merge] -- M4 -- M5 (master)

And now you wish you had done a "squash merge" or rebase of the feature branch onto the end of master rather than making a true merge.

The simplest way to do this is just to cherry pick the relevant commits one by one. Start a temporary branch at M3, and cherry pick F1, then M4, then M5. Now your temporary branch looks the way you wish master would look, so checkout master and reset it hard to your temporary branch and throw the temporary branch away.

git switch --det M3
git switch -c temp
git cherry-pick F1
git cherry-pick M4
git cherry-pick M5
git switch master
git reset --hard temp
git branch -D temp

That will form this, which seems to be what you want:

         -- F1 --
       /          \
M1 -- M2 -- M3 -- [merge] -- M4 -- M5 (was master, now nothing)
              \
               F1' -- M4' -- M5' (master, formerly temp)

The original M5, M4, merge, and F1 now have no branch name pointing at them, and so they will eventually be garbage-collected and the diagram will clean itself up:

M1 -- M2 -- M3
              \
               F1' -- M4' -- M5' (master)

I suppose it's possible to do something similar with an interactive rebase, but this simple step-by-step manual approach seems a lot more straightforward to me. In any case, rebase really is an extended series of cherry-picks, so the approaches are the same, without loss of generality.

Note that the usual caveats are in order here. You will be making copies of commits, so the new F1, M4, and M5 will have different SHA identifiers than the old ones. You are rewriting history, so you must not do any of this if master is shared with other collaborators, and if you have already pushed master, you will have to use force to push it after this change.

2
Martin G On

I'm not sure you have one or more commits in the feature branch, but i would hide the development history if you are delivering to the master branch. Add your feature contribution as one commit on top of master:

git checkout master
git merge --squash feature_branch