Michael Aranda

@michaelaranda0

Git Merge vs. Rebase: What’s the Diff?

Those who have eaten a chunk of wasabi thinking it was a chunk of avocado have learned the importance of distinguishing between two very similar things. Understanding the difference between Git’s merge and rebase commands may not be as essential to your physical well-being, but the point still stands.

git merge and git rebase offer the same service: incorporating commits from one Git branch into another. The key distinction lies in how this result is achieved.

Let’s find out how, shall we?

As Easy as ABC

We'll base our short discussion on the most meager “website” ever conceived. Initially, this website consists of a single page with the letters “ab” on it. That’s it.

This is going in the résumé.

Often in Git workflows, developers will create feature branches to work on new features in isolation. This gives them the freedom to make incremental commits for an in-progress feature without affecting the project’s master branch (more information about using feature branches can be found in Atlassian’s Git tutorials).

In our project’s Git repository, two branches currently exist: the usual master branch, and a feature branch that we created right after the initial commit. On the master branch, we have italicized the ‘a’, then bolded the ‘a’. On our feature branch, we have italicized the ‘b’, and then bolded the ‘b’.

The master and feature branches for the most complicated web project of 2017.
The commit logs/histories for the master and feature branches (read from top to bottom).

Let’s figure out how merge and rebase differ by going through a couple of typical Git workflow situations with this project.

Merge

We believe our redesign of the letter ‘b’ is nothing short of a masterpiece, so we decide we want to bring our work back into the master branch, incorporating it into the actual project:

git checkout master
git merge feature

By merging feature into master, master obtains a new commit — a “merge commit”.

Merging master into our feature branch. “Let’s just smush these branches together”.
Branch histories after the merge, with master’s new merge commit.

All by itself, the merge commit represents every change that has occurred on feature since it branched from master. Clean and simple.

The downside of merging? If used too liberally, merge commits can clutter up your Git logs, and make it much more difficult to understand the flow of your project’s history. For collaborative workflows in which other developers (and potentially even project managers/leads or QA) read your project’s Git logs for insight and context, readability is important.

An extreme example of merge-mania. Difficult to decipher, but at least the colors are pretty… Image Credit

To avoid this pitfall, try to use merges purposefully and sparingly. Avoid branching and merging when only making minor tweaks or trivial bug fixes. Use merge for cases where you want a set of commits to stand out.

Large refactors and major feature additions are good candidates for separate feature branches that can later be merged into master. As an added bonus, when merges are reserved for these major changes, the merge commits act as milestones that others can use to figure out when these major changes were incorporated into the project.

Rebase

Let’s rewind, and pretend that we instead wanted to keep working on styling the letter ‘b’ — maybe change its size, font, color, etc. We need to get it just right — this change affects 50% of our codebase! But before we continue working on our feature branch, we decide we want to bring in the latest changes from master to keep things fresh.

Rather than merging master’s new commits into feature, we opt to rebase our feature branch onto master.

git checkout feature
git rebase master

At a high level, rebasing can be understood as “moving the base of a branch onto a different position”. Think of it like a redo — “I meant to start here.”

The result of rebasing our feature branch onto master.

At a lower level, what rebase actually does is pluck commits from a branch one by one (chronologically) and re-attach them to a different commit. The point at which the branch…branched has now changed.

What actually happens when rebasing our feature branch onto master. We are essentially replaying the feature branch commits from a new starting point.

You might see from the diagrams above why we would choose to rebase instead of merge in this situation. Unlike with merging, rebase does not create an extra commit. This is ideal for our situation, since all we are currently trying to do is keep our feature branch up-to-date with any new commits from master. This is definitely not a meaningful event we want to preserve in our project’s history.

Although the changes on the newly rebased feature branch are identical to what they were before, it is good to note that, from Git’s perspective, these are new commits with new SHA’s (the commits’ identifiers).

But even more importantly, realize that the feature branch’s history has been completely rewritten. That sounds a bit heavy, doesn’t it? You might wonder if there are implications to this you should worry about.

An expert on time travel and its drawbacks: Barry Allen, flash-forwarding to a future of regret. Image Credit

Although unimportant when you are the only person working on a particular branch, reckless rebasing can be a major issue when collaborating with others. In short, the potential arises where others have copies of the branch checked out (with unaltered history) which conflict with your altered copy.

Pretend that another developer named Mark is working on the feature branch alongside you. He checked out the feature branch at its second commit — when the ‘b’ was italicized. While we rebased our version of the feature branch onto master, Mark innocently decided to add another commit on his own version, adding the letter ‘c’. Here is what the scenario would look like:

The master branch, our rebased version of the feature branch, and Mark’s copy of the feature branch. Notice the inconsistencies between our branch (bold) and Mark’s copy (blue). Not immediately obvious how to sort this out.

Even with our dead-simple project, it would take a little effort and brainpower to figure out how to resolve the discrepancies. Imagine trying to resolve this kind of conflict on a real-life, larger scale project. Not a lot of fun.

You can read more about the proper way to rebase here: The Golden Rule of Rebasing. The one-line summary: don’t rebase a branch unless you are the only one who uses it. Or you enjoy chaos.

Time to Make Like a Tree and Leaf

In summary, when looking to incorporate changes from one Git branch into another:

  • Use merge in cases where you want a set of commits to be clearly grouped together in history
  • Use rebase when you want to keep a linear commit history
  • DON’T use rebase on a public/shared branch

That’s all I got. If anything in the article was unclear, or you have any questions, comments, or suggestions, please feel free to leave them in the responses below! Thanks for your time!

Topics of interest

More Related Stories