Git: Merge vs Rebase
Tags: git, github, beginners
Published: 2021-03-11 12:23:26

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bsegnlkfmrpqdqcgjqbs.png)
*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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i1w8g1yal49wf8ov0b8u.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yuq70w51ndeyamg2r9dy.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hort65si10psqqtwav68.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jlrpbwrpbmkwf3r32vl9.png)

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](https://git-scm.com/docs/git-rebase#_interactive_mode)** 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

- [Git Merge - Atlassian Git Tutorial](https://www.atlassian.com/git/tutorials/using-branches/git-merge)
- [git rebase - Atlassian Git Tutorial](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase)
- [Merging vs. Rebasing - Atlassian Git Tutorial](https://www.atlassian.com/git/tutorials/merging-vs-rebasing)