Rebase in Git

Taking version control to the next level


12 Nov 2017 View Comments
#git #version #control #repository #rebase

Introduction

Here is a little background on myself with version control system. I remember using CVS (Concurrent Versions System) as my first repository back in mid-2000 in university. I literally had a very tiny knowledge of what the repository is and why it is required. When I joined my first software company, I started using the SVN (Apache Subversion) extensively. When I used it, it was very flexible in terms of how SVN generates diffs and handling the merges of my codes. I genuinely had an excellent workflow by enforcing the branching per issues and managing the trunk as the latest code setup. I was quite satisfied with it until I was exposed to GIT.

At first, I wasn’t sure whether I am going to get accustomed to GIT partially because I was already very familiar with SVN and there wasn’t much of a motivation to jump off the SVN ship. I eventually moved onto GIT as it was becoming quite popular. After a few years of using GIT, I love it, #nosarcasm. It is not only faster in general, but its fully distributed meaning there is no centralized server to handle the code handling. So when you are coding, commits are very tangible and malleable to the local machines. This is where the rebase in Git comes really handy. Rebase basically is recreating your work of one branch onto another (or the same). Rebase is really powerful and there are a couple of really handy tasks you can do with rebase. I would like to share some of the daily rebase tasks I often do.

NOTE: When I am explaining below, I would assume you are already familiar with the GIT flow. Also please note as it is important. Rebase means “copy commits, then try to forget the originals and use the copies instead”. This means “making a new history entirely”. This is the reason why you most likely need a --force during your push to the remote server. It could be a little annoying for other people to manage their repository linked to the branch I rebased. Since the new commits (after rebase) will have different hash, checking out the latest code by the traditional git pull is not going to work well. This is why it is best to stay away from rebasing when you are working with multiple people on the same branch. The issue branch is almost always owned and ran by me. So this problem rarely happens to me at least.

1. Fast-forward merge

Rebase is very handy when you try to merge stuffs. Here is an example using the feature branch and the master branch. Let’s say you have a master branch with X commit point and created a feature branch called feature. Here is how master branch looks like currently:

I’ve created a feature branch from this commit and made a few commits on top of it, like below:

Let’s make some complication by adding a commit in the master branch after this feature branch was created:

We now have few commits in feature branch but that does not have all the changes in latest master.

To put the changes in one place, we have choices between to merge or rebase.

  1. Using the command "merge" to merge

    Let's assume we would want to run the `merge` command and decided to bring changes from master branch to feature branch:
    $git checkout master
    $git pull // gets the latest change in master branch
    $git checkout feature
    $git merge master
    
    The result (shown below) leaves a dummy commit which specifies the code had been merged.
    What I normally do at this point is resolve all the conflicts and leave all the dirty stuffs handled inside the feature branch. Now when you are ready to merge feature branch into the master branch, we can run this command:
    $git checkout master
    $git merge feature
    
    This will merge the feature branch cleanly just by fast forwarding since feature branch and master branch is on the same path of commits. However, the dummy commit still follows:
  2. Using the command "rebase" to merge

    What if we want a structure commits so they are aligned well without any redundant merge commits? rebase is the solution! We have similar setup as above, and call rebase instead merge:
    $git checkout feature
    $git rebase master
    
    Notice there is no dummy commit because it restructured the commit history basically by running the rebase:
    Then when you merge similar to above:
    $git checkout master
    $git merge feature
    
    Another fast-forwarding here since the feature branch has the same commits of master branch plus the commits with the new feature branch.
    However, notice there is no dummy commit in the master branch either because it just fast forwarded whatever we have in feature to be the new master.

Regardless of a merge or rebase, you will run into the conflict. Some people think the rebase solves conflicts which are not true. You need to deal with conflicts one way or another. Rebase just makes the commits cleaner in my opinion.

2. Reword commits

Sometimes when you make a typo in your commit message or wording is just sounding not right that you want to change the wording of the commit message. You can use rebase to reword your messages. Initially, you have a feature branch with these commits:

You can then run,

$git rebase -i HEAD~2

2 is the number of commits you would like to rewrite using rebase, so in this case, it is 2 commits behind. Then there will a page popping up where you can change the pick to a reword:

After you put reword instead pick then save and quit, you are prompted to change your commit wordings in next screen. After you corrected your wording save and quit on that next page. GIT will do the rewrite your history by rebasing. Check your commit logs updated.

Here I showed just an example of rewording one commit. You can, however, reword as many commit messages as you wish.

3. Combine commits

Many times commits are better with a single commit because simply those commits are related to each other. It will be much more organized once you have these separated out by their own means rather than having multiple commits all crowded. We can use the “squash” feature from the rebase in GIT for this.

With the same setup above, we are in a feature branch of some # of commits:

Run the rebase command again:

$git rebase -i HEAD~2

Here you can put ‘squash’ instead of ‘pick’:

When you save and quit, you will be prompted to edit commit message, here you can give your reasons to whats being combined or simply keep the oldest commit message. After editing the message, you can see your git log is displayed in one commit:

4. Delete commit(s)

Well, obviously there are times when a commit is no longer necessary. You can delete the entire line of unnecessary commit by deleting the entire line using the rebase in GIT.

You can also pick and choose whatever the commits you need to get rid of, let’s say you have a repo with multiple commits:

Say you want the “Change 2” and “Change 4” deleted from this branch. Run the following to cover everything until “Change 2”

$git rebase -i HEAD~4

When you have a screen popup, delete those commits, “Change 2” and “Change 4”:

After removing those lines, save and quit. You might run into a couple of conflicts in between, resolve them, hit git rebase --acontinue to complete those tasks.

Once you have done rebasing, those commits should be gone:

Conclusion

These rebase tasks are some of common ones I do daily to make commits happy. Obviously, you are going to get familiar a lot quicker if you start using GIT itself. In addition, there are a couple more rebase tasks you can do such as re-ordering commits, separate out portion of code into a separate commit, “fixup”, or even exec where you can run command within GIT commit. Also, I’d like to add that git commit --amend is really just a rebase of the most recent commit. If you know the power of amend, extend the power to all the other commits!

Share this post

Me

I am a passionate software developer working in Downtown, Vancouver. I strongly believe in art of algorithms and together with it to write clean and efficient software to build awesome products. If you would like to connect with me, choose one from below options :) You can also send me an email at