In my current work project we always squash commits on merge. This means that whenever a branch is merged, all of its commits are combined into one commit. Imagine we have the following
F---G feature-Y
/
D---E feature-X
/
A---B---C master
We started work on feature-X and then went on to make some more changes on the feature-Y branch. This usually happens when feature-X already has a pull request open and another developer wants to start working on the next feature which is going to be based on the former pull request.
Now, as I said above, in my current work project, we always squash commits on merge.
After merging feature-X, our state is going to be (approximately) this:
F---G feature-Y
/
D---E feature-X
/ \
A---B---C------(DE) master
In order to now create a clean pull request for feature-Y, we would like to rebase this branch on the latest commit on the master branch so that our graph looks like this:
F---G feature-Y
/
A---B---C---(DE) master
Usually, what we would do to rebase feature-Y is this: git checkout feature-Y
, then git rebase master
. This is not going to work in this case though. When we are on the feature-Y branch, git tries to match the commits to the commits on master. In our case, commit D
and E
cannot be found on master anymore though as they have been squashed into another commit (DE
). This means that we will get conflicts when trying to apply them.
Luckily, we as the developers know better and we can tell git explicitly that it should only take the two most recent commits and rebase those. We do this by executing the following command: git rebase --onto master HEAD~2
. This way, we tell git that it should take the last two commits from HEAD and put those on top of master. When we execute this, we don’t get any conflicts and get just the result that we want.
Note that we could also have used git rebase --onto master feature-X
here since HEAD~2 and feature-X actually point to the same commit when we are on feature-Y.
I have solved the same problem before by creating another branch of master and then cherry-picking just the commits from feature-Y that I wanted to move over but this is a much nicer solution. I learned about this in this post by Daniel Straßner so make sure to check that out to learn more. For a more visual representation you can also check out this post by Tobi. The man page for rebase
is also quite detailed and has lots of nice ascii-art. So more examples are just a man git-rebase
away!