The scenario is there are some changes you like to apply on another branch. For example I have different version of my JIRA plugins for JIRA 6 and JIRA 7 versions due to incompatible APIs between them. This two branch will be never merged with each other and as long as I continue to support JIRA 6 I need to fix issues and introduce new features on both branches. For one line fixes it is easy to checkout branches one by one and apply the fix but for larger changes I need to apply a set of commits exactly to another branch.
Here is the state of repository after we have finished our feature.
We want to copy F1, F2, F3 to both master and V1 branches. As you can see we had branched from master, so it is extremely easy to merge New_Feature branch to master. But we can’t merge New_Feature branch to V1 branch, because merging it will try to merge everything until it finds a common ancestor for New_Feature branch and V1 branch. So for this case, in addition to F1, F2, F3, it will also try to merge C4 and C5 commits, which we don’t want because these commits are specific to master branch.
git rebase is one of the powerful git commands that requires great responsibility while using. Never rebase a published branch. If you are considering to merge two branches some time in the feature, use merge instead of rebasing because although exactly the same change in terms of file changes, commits introduced by rebase are different commits, because they have different parents.
Ok, how do we merge this changes without manually performing each change in the other branch? There are several ways to achieve this. We can use ‘cherry-pick’ or ‘rebase’. Lets see how we can achieve it with rebase, although cherry-pick is more simple solution rebase is a more flexible command.
rebase takes a series of commits and apply them onto another commit one by one. *It does not move commits, it reapplies them onto another commit, leaving the original commits in place as long as we have a pointer to original commits, we won’t loose them. For not loosing them after we move the branch pointer, lets create another branch pointing to the same feature branch.
Now we have two pointers pointing to the same commit, we can move our New_Feature_V1 pointer freely. Using this pointer we can rebase commits F1, F2 and F3 onto V1.
This command will take all the commits between New_Featuer_V1 (Included) and C5 (Excluded) and apply them one by one on top of V1. Resulting repository structure will be as follows:
Only thing remained is moving our V1 pointer, and doing a simple merge will fast forward our V1 to New_Feature_V1.
This will leave us with the following repository:
If you want, you can delete New_Feature_V1 branch with following command. We don’t need it anymore because it is pointing to the same commit as V1.
Lets see how we could do this with cherry-pick:
This is easier but rebase -i flag allows you to perform an interactive rebase and you can squash, omit some commits if you want.
There are a lot of good resources for learning Git, but my favorites are: