Rebase vs. Merge: Pros and cons

A simple explanation of how merge and rebase work along with some use cases to help you choose the best approach.
Heading Product Experience for Peekaboo Guru & Peekaboo Connect. From designing experiences to converting them into functional products

Rebase vs. Merge: Pros and cons

A simple explanation of how merge and rebase work along with some use cases to help you choose the best approach.

Managing repository history is one of the critical parts of keeping your code base scalable. Many approaches might be helpful in one case and not work in another. Here we will discuss how git merge and git rebase differ from each other.

Let’s have a look at how both commands work.

Git rebase

As the git official docs state: “Reapply commits on top of another base tip,” this reapply will place all commits on the current branch on top of the target branch. Let’s take an example here:

Assume the following history exists and the current branch is a feature:

           A---B---C feature

         /

    D---E---F---G main

From this point on, feature as the result of the following commands:

git rebase main

would be:

                   A'--B'--C' feature

                 /

    D---E---F---G main

Now all the commits done on the feature branch are re-aligned on top of the new state of the main branch. During this process, all commits on the feature branch are rewritten and have new commit IDs. If there is any conflict in between the rebasing process, git will stop the process and ask you to resolve conflicts before proceeding.

Here are the options available with the git rebase command.

Git merge

According to the official docs: “Join two or more development histories together,” it is a non-destructive operation that adds a forked stream on top of the target stream without rewriting commits. 

Here is what it will look like in our example:

Assuming the feature  branch is forked from the main branch, with the main having commits applied after the fork was created, the state of the repository will look like this:

           A---B---C feature

         /

    D---E---F---G main

From this point on, the feature:

git merge main

Would result in the following output:

          A---B---C feature

         /         \

    D---E---F---G---H main

Here, H is the new commit on top of the feature branch that has the full stream coming from main.

A new commit will be created on the feature branch that might feel unnecessary. But, on the flip side, the commit history is intact and commits are not re-written. Git will ensure the merge is safe and will prompt in case of any conflicts just like the rebase command.

This is what our feature branch will look like now.

Differences

Both commands as seen may offer similar results but differ in how they achieve them. These differences can have a significant impact on how your commit history looks in the long run.

We have identified a few of the most important differences that can help you better understand both; Remember we aren’t establishing any conclusions just yet, we will discuss pros, cons, and use cases later in the post.

Commit logs

For merge it keeps the commit history intact with the merge commit showing on top, while rebase rewrites, it means the timestamp of actual commits is lost and new commit IDs are created.

Commit history

On the other hand, when the feature branch is merged in main, it may create a single commit so the implementation details go away after merge. Rebase eliminates the extra merge commits and makes commit history linear with all commits of feature lined up together.

Conflict resolution

Both commands handle conflicts differently – merge being more focused on bringing the stream on top of the other will show conflicts at once, while rebase processes one commit at a time. Hence, it presents conflicts on each commit.

Benefits

Both commands in the discussion are super useful in their own capacity. Let’s dive into what each command offers as compared to each other.

Merge

  • Simple & easier to handle, it can be done via most git management UIs
  • Timestamps of commits are maintained which might be necessary in some regulatory cases.
  • Maintains all activity done on the branch as it occurred.

Rebase

  • Streamlines a commit history for a feature allowing other devs to see how feature was implemented
  • Avoids extra merge commits that to keep commit logs clean
  • Possibility to truncate useless commits to make sure only significant changes are logged in git logs. 

Pitfalls

Just like benefits, there are certain pitfalls associated with both commands, we have listed a few of them to help you avoid mistakes that can be costly in the future.

Merge

  • ⚠️ Merging public branch to feature will make it ugly, commit history is an important tool for debugging. Having a linear commit history will help diagnose future issues.
  • ⚠️ Resolving conflicts with merge can be tricky as it brings all commits from the source at once.

Rebase

  • ⚠️ Never use rebase  on a public branch, it rewrites the commit history and requires force push which should be prohibited on public branches.
  • ⚠️ You might be a fan of rebase due to its simplicity. But, keeping your entire history may be essential to meet regulatory and compliance requirements.
  • ⚠️ The learning curve for rebase can be steep for teams, but the fruits it bears are worth all the effort that goes into it.

Use cases

Feature Branch Sync With Main [ Rebase ✅ | Merge ⚠️]

This use case is the best fit for rebase command, as we have seen in the examples above, having a feature branch forked out of main has to be in sync with main before we merge it.

In such cases rebase works best as it will bring all feature-based commits together on top of main resulting in a linear history of how feature was developed. With merge, it produces an extra commit on the feature branch and might be a little tough on resolving conflicts.

Updating a public branch [ Rebase ❌ | Merge ✅ ]

When your features are ready to be shipped into public branches (e.g develop, main, staging, etc.) it’s always the merge command that one should use. The golden rule for rebase says “Never rebase public branches”.

Since rebase rewrites commit history it requires force push to sync the remote branch with a new commit history. It is highly recommended to keep your public branches protected and stop force push on these branches. For public branches, rebase is not appropriate.

Squash Intermediate Commits – Cleanup [ Rebase ✅ | Merge ❌ ]

During fast-paced development, we tend to create many intermediary commits that must be removed before we push our code to remote. In such cases, only rebase with interactive mode is a solution that allows us to drop, squash, and reword commits in our stream. 

Conclusion

In most scenarios, we use both of these super helpful commands in the same repositories.

For most of the use cases each time a feature branch is ready to be shipped in the public branch, it is rebased on top of public branch and then merged (squashed or rebased) in the public branch. An in-depth understanding of both commands will allow you to leverage all the best they offer to make your commit history more clean and readable.

I am always looking for more use cases to discuss, feel free to comment below. I’d love to have a healthy discussion around it! thought balloon 

Aviator: Automate your cumbersome merge processes

Aviator automates tedious developer workflows by managing git Pull Requests (PRs) and continuous integration test (CI) runs to help your team avoid broken builds, streamline cumbersome merge processes, manage cross-PR dependencies, and handle flaky tests while maintaining their security compliance.

There are 4 key components to Aviator:

  1. MergeQueue – an automated queue that manages the merging workflow for your GitHub repository to help protect important branches from broken builds. The Aviator bot uses GitHub Labels to identify Pull Requests (PRs) that are ready to be merged, validates CI checks, processes semantic conflicts, and merges the PRs automatically.
  2. ChangeSets – workflows to synchronize validating and merging multiple PRs within the same repository or multiple repositories. Useful when your team often sees groups of related PRs that need to be merged together, or otherwise treated as a single broader unit of change.
  3. FlakyBot – a tool to automatically detect, take action on, and process results from flaky tests in your CI infrastructure.
  4. Stacked PRs CLI – a command line tool that helps developers manage cross-PR dependencies. This tool also automates syncing and merging of stacked PRs. Useful when your team wants to promote a culture of smaller, incremental PRs instead of large changes, or when your workflows involve keeping multiple, dependent PRs in sync.

Try it for free.

Aviator.co | Blog

Subscribe

Be the first to know once we publish a new blog post

Join our Discord

Learn best practices from modern engineering teams

Get a free 30-min consultation with the Aviator team to improve developer experience across your organization.

Powered by WordPress