Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rebase after a merge?

We have a sequence of events like this:

  1. Create branch A, and add a few commits to it
  2. Time passes, hundreds of commits added to master
  3. Master is merged into A
  4. Time passes, maybe another 50 commits added to master

Is it possible to turn the merge in step 3 into a rebase? If nothing else, it would make the impending merge simpler as there would be less history to look at.

We haven't had rerere enabled.

like image 737
Steve Bennett Avatar asked May 15 '12 10:05

Steve Bennett


1 Answers

Consider the following Git graph:

A...C...D...F
^       ^   ^ master
 \       \
  G...H...I...J
              ^ feature

The ... means "lots of commits".

Suppose we want to essentially rebase, i.e. take the commits in feature's history but not in master's history and reform them as a linear sequence of commits in master. This confounded by the fact that we merged master into feature at commit I. If we try to rebase, Git screws up because it tries to apply e.g. C on top of master and finds conflicts.

We can solve this problem by grabbing the actual changes from feature and packing them into a new commit. Here's a way to do this using only very basic Git commands:

(1) git checkout feature
(2) git merge master
(3) git reset A
(4) git add -A  # This stages all working copy changes
(5) git commit -m "Every change between A and J"

In step (2), the feature branch has all changes in both master and J. After step (3), HEAD points at A, but our working copy has all the changes from master and J, and steps (4) and (5) stage and commit those changes.

At this point our graph looks like this

A...C...D...F
^           ^ master
 \
  J'
  ^ feature

Note that J' contains everything in A...F. Now we do

git rebase master

Git happily applies the changes in J' as a new commit J'', but the only changes to add are those in G...J because the other changes are already in master. So now we have

  A...F<--J''
master^   ^feature

with all of the changes in our feature branch squashed into commit J''. At this point, you can reset to F and re-apply changes in J'' in a more granular fashion (even using git add --patch) if you want.


Another way to do essentially the same thing is with read-tree as explained in this other answer

git checkout master
git read-tree -u -m feature

Yet another way to do the same thing, stolen from this answer, is

git diff master > feature.patch
git checkout master
patch -p1 < feature.patch
like image 126
DanielSank Avatar answered Oct 16 '22 14:10

DanielSank