DEV Community

Ravi Suresh Mashru
Ravi Suresh Mashru

Posted on

Git: Merge vs Rebase

I personally struggled to understand the difference between merging and rebasing in Git, especially since they both did what I wanted in the end (bring changes in another branch into my current branch), until I visualized what exactly happens in both processes.

To compare the two, let us assume that the main branch of your repository is where all the code is kept up-to-date.

commit history of main branch
Each circle in the sequence represents a commit. An arrow goes from a parent commit to a child commit (from a previous commit to the next commit).

To work on a new feature, you check out a new branch cool-feature and make a few commits.

commit history of main branch with feature branch checked out with new commits

In the meantime, some of your team members finished a feature they were working on and merged their commits to the main branch.

commit history of diverged main and feature branch

You now need to bring the new changes in the main branch into your cool-feature branch.

Git Merge

If you want to merge the changes into your branch, you would run the command git merge main while still on your cool-feature branch.

This will replay the changes contained in commits on the main branch since the first common commit between the two branches. A new merge commit will be created in your cool-feature branch that contains all the latest changes from the main branch.

If both branches have changes to the same lines, then Git cannot determine which of the two changes to keep (the one in the main branch or the one in the cool-feature branch). This results in what Git calls a conflict that the user has to resolve. After making necessary changes in the file that has a conflict (i.e. deciding whether to keep the changes from the main branch, the cool-feature branch or a mix of both) the user can commit these changes as a part of the merge commit created.

The merge commit has two parent commits: the latest commits on both the branches.

commit history after merging main branch with feature branch

The algorithm Git uses to merge changes this way is called the 3-way merge algorithm because it uses three commits to generate the merge commit:

  1. The latest commit on the main branch.
  2. The latest commit on the cool-feature branch.
  3. The latest commit that is common in both branches.

Git Rebase

To perform a rebase, you would run the command git rebase main while on your cool-feature branch.

This will replay each commit in your cool-feature branch on top of the latest state of the main branch. For each commit in your cool-feature branch, a new commit will be created which contains the same changes as the initial commit.

commit history after rebasing feature branch on main branch

In case there are conflicts when applying each commit, Git will stop rebasing and notify you so that you can resolve them. The changes you make to resolve the conflicts will be added to the new commit.

Git also gives you the option of performing an interactive rebase where you can decide what to do with each commit that will be reapplied to the main branch.

Which One Should You Use?

The first question I asked myself after understanding the difference between the two was: which one should I use?

Not surprisingly, like most things in software engineering, the answer turned out to be it depends. Merging and rebasing give you two completely different views of your repository's commit history.

The downside of using merge is the creation of merge commits that can clutter the commit history of your repository. In a project where a lot of changes are actively being added to the main branch, your feature branch will have a new merge commit in it every time you merge it with the main branch. This can make it difficult to clearly see the actual commits you are making to implement the feature.

On the other hand, using rebase is not as straight forward as using merge. Since rebasing re-writes history (by dropping old commits and creating new ones), rebasing a branch that you have previously pushed (e.g. to GitHub) and others have started using can cause problems. You will now have a different commit history after the rebase from what others accessing the same branch have. If they do not pull this new rewritten history, they will be working on an outdated copy of the branch. This might become a problem when they try to push their changes in a branch with an outdated history.

Personally, if I am working on a feature branch that I have not yet pushed upstream (and as a result no one would have checked it out), I use rebase to avoid the extra merge commit. However, if the branch I am working on has already been made public, I avoid rewriting history with a rebase and live with the extra merge commit.

Further Reading

Discussion (0)