Git Merge vs. Rebase: Which to Use and When

One of the most powerful features of Git is its ability to create “branches” of a codebase that can be developed in parallel. This lets multiple team members contribute to different features simultaneously without stepping on each other’s toes. But sometimes, a feature branch gets out-of-date with its parent branch. There are two popular strategies for reconciling this: merging and rebasing. In this post, we’ll weigh the pros and cons of both options and help inform your decision to use one or the other.

The Scenario

Let’s say you have two branches, main and feature. The feature branch was originally based off main, and new changes have appeared on main since then.

Two Git branches, main and feature. The feature branch was based off main, and new changes have been made on main since then.

Git Merge

Merging is a strategy that allows you to incorporate the main branch’s changes into your feature branch via a “merge commit.” While on the feature branch, you can perform this by running the following:

git merge main

This results in the following branch structure, with the * representing a merge commit:

Two Git branches, main and feature. The main branch has been merged into feature and the merge commit is marked with an asterisk.

Merging is a simple, easy way to pull in the latest changes from a base branch. Conflicts can be handled all at once, and a merge can easily be reverted if you make a mistake. This makes merging a great option while you’re first getting started with Git.

However, merging in the main branch every time it changes can muddy up your feature branch with extraneous merge commits and make it hard for other contributors to follow the history of the branch. Many Git tools have workarounds for this. The Git CLI, for example, allows you to use the --no-merges flag to filter out merge commits in your git log.

Merging allows easy co-ownership of branches. It maintains your commit history as it happened — no rewriting or reordering of commits. This makes it easy for multiple teammates to work on the same branch, which, as we’ll see, isn’t always the case with rebasing.

Git Rebase

Rebasing is a strategy that re-applies all of the changes from your feature branch on top of the head of the main branch. Instead of creating a merge commit, rebasing will rewrite the entire history of your current branch, as if the work had been re-done on top of a different head.

git rebase main

This results in the following branch structure. Notice how the commits from the feature branch have moved to the head of main:

Two Git branches, main and feature. The feature branch is based off the head of the main branch.

This can drastically improve readability by making your branch’s history linear — one step after another, with no extraneous merge commits.

Rebasing also allows you to reorder and redistribute your changes to clean up the history of a branch. For example, you can squash together “WIP” commits and synthesize them into more meaningful changes. Plus, if you make an embarrassing mistake on a branch (say, exposing a secret key in the source code), rebasing allows you to remove any traces of that mistake. (In contrast, with a merge, the mistake would still exist in the Git history.)

Rebasing, when done right, can make your branches easier to read and review. But it’s a double-edged sword: rebasing is a destructive action. If you mess up a rebase, there’s no going back (at least not without some shenanigans). Because rebasing rewrites the commit history, your branch can get out of sync with other people working on the branch, causing confusing errors when trying to synchronize changes.

Note that to push a rebased branch to a remote repository (e.g. GitHub), you have to force-push. I like to use --force-with-lease to make sure I’m not overriding any changes that have happened upstream.

Git Merge or Rebase?

Advocates of Git Merge argue that merging prevents the potentially-catastrophic consequences of a nasty rebase. Because merging is a simpler, less error-prone way to achieve the same goal as a rebase, they argue that it should be preferred. Maintaining the history of changes can also help future developers step into the shoes of past developers, building empathy and giving insight into the choices and tradeoffs made at the time the code was written.

On the other hand, advocates of Git Rebase emphasize the importance of a clean, readable history. They argue that keeping your history pristine not only eases the code review process but also helps prevent future developers from repeating outdated patterns. They claim that developers should know their tools like a chef knows his knives. Reaching for the “easier” option gets the job done, but it doesn’t deepen your understanding of how Git works as a whole.

Both sides have strong arguments, so I don’t tend to lean toward one or the other. At the end of the day, merging and rebasing are two different means to the same end: getting a branch up-to-date with its parent. Instead, I use this rule of thumb, and I’d encourage you to follow it as well: if you’re working on a branch by yourself, rebase away! If you’re working on a branch with other people, prefer merging instead.

Do you prefer merging, rebasing, or some mix of both?

Conversation

Join the conversation

Your email address will not be published. Required fields are marked *