Normally, there's an ad running in this spot, but you're using an ad blocker. To help support our blog, which provides free tutorials for everybody, we just ask that you whitelist or follow us on facebook, twitter, or subscribe using the form to the leftabove. Thank you!

    Git Merge vs Git Rebase

    Today, we're comparing two popular Git branching strategies. We won't be going over other revision control alternatives like Subversion(SVN), mercurial, or TFS, here.

    Visualizing Git Branches

    Think of git code as this tree like structure. The master is your trunk. That's all of your code in one state. The process of adding and committing is, in essence, taking snapshots of your changes, along the way. To make it easier to maintain your code, you're going to want to make branches off of the trunk, and commit code to those branches. Once you've finished programming and testing the feature, you'll merge that branch back into the trunk. Otherwise, you can just leave the branch where it is or delete it. The key thing to note is that branches/features are isolated from each other until while development is in progress. That's git branching in a nutshell. It's easy to see the differences between merging and rebasing in SourceTree.

    A Basic Merge Workflow

    Create a new git repository by following the instructions on GitHub's documentation. The following git intialization steps are also provided in the documentation, but I'll list them out here, anyway.

    Initialize a new repository and link to the remote repo..

    mkdir my-project
    cd my-project
    echo "# my-project" >> README.md
    git init
    git add README.md
    git commit -m "first commit"
    git remote add origin git@github.com/myorganization/my-project.git
    git push -u origin master
    

    This next step creates a develop branch off of the master trunk.

    $ git checkout -b develop
    Switched to a new branch 'develop'
    

    Next, we'll create our first feature branch. The convention to use when making feature branches off of develop is firstinitial_featurename.

    $ git checkout -b rl_feature_a
    Switched to a new branch 'rl_feature_a'
    
    $ touch text.txt
    
    $ git add text.txt
    
    $ git commit -m "Added text file"
    [rl_feature_a a8a5bdb] Added text file
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 text.txt
    
    $ git push origin rl_feature_a
    Counting objects: 3, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (3/3), 277 bytes | 0 bytes/s, done.
    Total 3 (delta 0), reused 0 (delta 0)
    To git@github.com:codeboxsystems/my-project
     * [new branch]      rl_feature_a -> rl_feature_a
    

    When we're done commit our changes to the feature branch, and we've run our unit tests, it's safe to merge the branch into develop.

    $ git checkout develop
    Switched to branch 'develop'
    
    $ git merge rl_feature_a
    Updating ea64565..a8a5bdb
    Fast-forward
     text.txt | 0
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 text.txt
    

    Here, we're pushing our version of develop to the remote repository so that everyone else on our team has our changes.

    $ git push origin develop
    Counting objects: 3, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (2/2), 247 bytes | 0 bytes/s, done.
    Total 2 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
     * [new branch]      develop > develop
    

    Now, this is where we "freeze" the develop branch were it is and make an rc branch for QA. This gets made into it's own separate 0.1.0-rc.1 branch off of develop. No further development will be made on this branch in case unless QA points out a bug. Any further development should be made on feature branches. If we were to make changes to the release candidate at this stage, without QA knowing, we'd be invalidating all of their testing.

    $ git checkout -b 0.1.0-rc.1
    Switched to a new branch '0.1.0-rc.1'
    
    $ git push origin 0.1.0-rc.1
    Total 0 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
     * [new branch]      0.1.0-rc.1 > 0.1.0-rc.1
    

    Now it's QA's job to test the software running on versin 0.1.0-rc.1. After the release candidate passes QA, we merge the branch into master.

    $ git checkout master
    Switched to branch 'master'
    Your branch is up-to-date with 'origin/master'.
    
    $ git merge 0.1.0-rc.1
    Updating ea64565..a8a5bdb
    Fast-forward
     text.txt | 0
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 text.txt
    

    Finally, we tag our release, making it show up in the "Releases" section of our remore repository where the archived package can be downloaded.

    $ git tag -a 0.1.0 -m '0.1.0 release'
    
    $ git push origin master
    Total 0 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
       ea64565..a8a5bdb  master > master
    
    $ git push --tags
    Counting objects: 1, done.
    Writing objects: 100% (1/1), 161 bytes | 0 bytes/s, done.
    Total 1 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
     * [new tag]         0.1.0 > 0.1.0
    

    Rebasing

    When rebasing, you are rewriting history. So instead of multiple pathways that intertwine around the trunk, you get a linear representation of the history. While the result is much cleaner than merging, you are essentially flattening all the branches, and fast forward merging. And then you end up resetting the base commit to the most recent commit of the branch you're merging into.

    Let's create a new feature branch.

    $ git checkout develop
    
    $ git checkout -b rl_feature_b
    Switched to a new branch 'rl_feature_b'
    
    $ touch textb.txt
    
    $ git add textb.txt
    
    $ git commit -m "Added another text file"
    [rl_feature_b 38c4fd7] Added another text file
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 textb.txt
    
    $ git push origin rl_feature_b
    Counting objects: 2, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (2/2), 278 bytes | 0 bytes/s, done.
    Total 2 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
     * [new branch]      rl_feature_b -> rl_feature_b
    

    Now rebase the feature into develop.

    $ git checkout develop
    Switched to branch 'develop'
    $ git rebase rl_feature_b
    First, rewinding head to replay your work on top of it...
    Fast-forwarded develop to rl_feature_b.
    

    Cut a release candidate.

    $ git checkout -b 0.2.0-rc.1
    Switched to a new branch '0.2.0-rc.1'
    
    $ git push origin 0.2.0-rc.1
    Counting objects: 3, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (2/2), 256 bytes | 0 bytes/s, done.
    Total 2 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
     * [new branch]      0.2.0-rc.1 -> 0.2.0-rc.1
    

    And rebase the release candidate into master.

    $ git checkout master
    Switched to branch 'master'
    Your branch is up-to-date with 'origin/master'.
    
    $ git rebase 0.2.0-rc.1
    First, rewinding head to replay your work on top of it...
    Fast-forwarded master to 0.2.0-rc.1.
    
    $ git tag -a 0.2.0 -m '0.2.0 release'
    
    $ git push origin master
    Total 0 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
       a8a5bdb..38c4fd7  master -> master
    
    $ git push --tags
    Counting objects: 1, done.
    Writing objects: 100% (1/1), 162 bytes | 0 bytes/s, done.
    Total 1 (delta 0), reused 0 (delta 0)
    To git@github.com:myorganization/my-project.git
     * [new tag]         0.2.0 -> 0.2.0
    

    Did you like this tutorial? Help us pay for server costs by following us on Facebook, Twitter, and subscribing below, where you'll get post notifications, training webinar invites, and free bundles.