loading...

Git Merge vs Git Rebase

neshaz profile image Nesha Zoric ・3 min read

Git merge and rebase serve the same purpose – they combine multiple branches into one. Although the final goal is the same, those two methods achieve it in different ways. Which method to use?

What Does Merge or Rebase Mean?

Here you have a sample repository that has two diverging branches: the master and the feature. You want to blend them together. Let's take a look how these methods can solve the problem.

git-flow

Merging

When you run git merge, your HEAD branch will generate a new commit, preserving the ancestry of each commit history.

git-merge-2

Fast forward merge is a type of merge that doesn't create a commit, instead, it updates the branch pointer to the last commit.

Rebasing

The rebase re-writes the changes of one branch onto another without creating a new commit.

For every commit that you have on the feature branch and not in the master, a new commit will be created on top of the master. It will appear as if those commits were written on top of master branch all along.

git-rebase

Merging Pros and Cons

Pros:

  • Simple to use and understand.
  • Maintains the original context of the source branch.
  • The commits on the source branch are separated from other branch commits. This can be useful if you want to take the feature and merge it into another branch later.
  • Preserves your commit history and keeps the history graph semantically correct.

Cons:

  • History can become intensely polluted by lots of merge commits because multiple people are working on the same branch in parallel. Visual charts of your repository are can become a mess and don't add too much information. It can look like a London Tube Map Commit!

london-tube-map-commit

Rebasing Pros and Cons

Pros:

  • Code history is simplified, linear and readable.
  • Manipulating a single commit history is easier than a history of many separate feature branches with its additional commits.
  • Clean, clear commit messages make it better to track a bug or when a feature was introduced. Avoid polluting history with 20+ single-line commits!

Cons:

  • Lowering the feature down to a handful of commits can hide context.
  • Rebasing doesn't work with pull requests, because you can't see what minor changes someone made. Rewriting of history is bad for teamwork!

    You need to be more careful with rebasing than when merging.

  • It requires more work when dealing with conflicts. Using rebase to keep your feature branch updated requires that you resolve similar conflicts again and again. While with merging, once you solve the conflicts, you're set. You have to resolve the conflict in the order they were created to continue the rebase.

Which Method to Choose?

When your team uses a feature based workflow or is not familiar with rebase, then git merge is the right choice for you:

  • It allows you to preserve the commit history for any given feature while not worrying about overriding commits and changing history. It helps you avoid unnecessary git reverts or resets!
  • Different features remain isolated and don't interfere with existing commit histories.
  • Can help you re-integrate a completed feature branch.

On the other hand, if you value more a clean, linear history then git rebase may be most appropriate. You will avoid unnecessary commits and keep changes more centralized and linear!

If you rebase incorrectly and unintendedly rewrite the history it can lead to serious issues, so make sure you know what you are doing!


Rebase or merge, what is your preference? Kolosek team leans more towards merge for our feature-based workflow.

This article is originally published on Kolosek Blog.

Posted on May 28 '18 by:

neshaz profile

Nesha Zoric

@neshaz

Founder/CTO at Kolosek. Building tech startups. Starting project? Contact at https://kolosek.com

Discussion

markdown guide
 

Simple solution: disallow rewriting history on your server (aka. git push --force MUST not be allowed, ever). This will prevent people from pushing rebased history.

It's considered good behavior to rebase before you create your pull request. Lots of OSS projects will insist on this. You decide this before you push local changes. And in the case of OSS projects it is up to them whether they will pull your changes.

Avoid doing squash merges unless you can afford to get away with them. That means you don't want to have multiple long lived branches having to deal with solving conflicts on insanely huge diffs resulting from somebody squashing huge amounts of changes. With a normal git merge, you solve conflicts commit by commit, this is great because the scope of these is usually fairly limited meaning conflicts are typically straightforward to deal with.

If you squash two weeks of work into one commit, it's like saying "we don't give a shit about versioning here; enjoy this huge diff without any context whatsoever". Don't do that. This will cause lots of work in long lived branches when they need to sync up. So, squash if you absolutely must but be mindful of the havoc you create upstream with your huge diffs. I tend to not use them. Not worth the problems they cause.

Related to that, keep any branches you care about up to speed with what they eventually have to be merged back to. Bi-directional merges just work in git and long lived branches are why you need them. Don't be afraid to use them. Knowing things will merge cleanly because you already merged the upstream changes and solved all the conflicts, is a good thing.

You might argue that feature branches are bad but the reality is that pull requests stay open for hours, days, or in some cases weeks while people collaborate on them. Shit happens in between when you create a PR and when you merge one. The bigger and more complicated your project, the more this will happen. Git was designed to facilitate this, not obstruct it. Use it properly.

 

Simple solution: disallow rewriting history on your server (aka. git push --force MUST not be allowed, ever). This will prevent people from pushing rebased history.

We use strategy where force push is disallowed for main branches (e.g. master) but allowed for individual developer branches. This way developers can commit freely and the history can be cleaned up before the changes are taken to master (while also being able to push the intermediate work to remote).

 

If you squash two weeks of work into one commit,

😱

 

Hey, Jilles, thank you for sharing your opinion with the community! Kolosek team mostly works around feature branches and pull requests with weekly sprints. Our goal is to achieve the best results in a timely manner by keeping the features small enough to be completed on time and easy to bug fix in case that is needed.

 

For someone working alone, rebase isn't a big deal. If you're working with a team or on a public repository, I just don't see any benefit to striving for a linear history. Squash commit + merge is easy enough to read, and much safer.

A comparison I would rather make is between the git branching model and the GitHub Flow models, the former I think better for large teams, and the latter for simpler projects.

Work to suit the project, not the commit graph aesthetic. :)

 

Thank you for writing - I agree merging makes more sense and I would go as far to say it is a design mistake for a version control system to even allow for history/commits to be altered or overwritten (maybe unpopular opinion).

Likely even more unpopular and controversial... every time I read a git article (and this is in no way a criticism of this article in particular, which I think is well written) I am reminded that we need something better than the user hostile git (your using it wrong...!). I don't think version control has been solved properly yet by any tool.

That isn't intended as a negative comment - I think we can and eventually will do better. I believe that will eventually take the form of a more opinionated and conceptually simpler hybrid which combines the best points of distributed and centralised systems.

 

That's an interesting idea and would be nice to see it implemented in the future. The more variety the better!

 

The second image on this page is incorrect (git-merge-2.png). It shows a green dot before master and after merging this with the branch. This is how the image should be after the merge:

If you were in the master branch and then "git merge feature-branch", then you get:

--()--()--|---()--(feature branch HEAD)---|
\ \
-- ()-- (green commit)--------(master HEAD)

Note that master is incremented and it contains the feature branch now. The existing master branch commits are before the merge. In your image they appear after the merge which is wrong.

 

Good post! I'm kinda new to Git and I also think that Merging is the safer and easier way when you're working with a team that develops very similar features or features that are very related to each other. One question I still have is what should I do when I'm done with the "feature" branch? should I delete the branch and continue working in another one? or will that affect the repo history?

 

When you have already merged your repo to the master you can just delete the branch.

 

Sweet, I was looking into this exact topic on the week it was written!
The default behaviour on most services will create "merge commit" when pushing or using the web interface.
Would be great if there are ways to configure those behaviors with a github.yml/gitlab.yml or something.

e.g. Github client only has merge for branches.

 

We use rebase when updating from remote and merge to keep feature branches to to date.

Changing the history is prohibited for all Devs.

 

Agreed. However, that is not necessarily a bad thing at all, especially when you are dealing with pull requests and feature branches. Having preserved commit history can make it easier to find and fix bugs and overall improves working on a group project.

 

Working with shared repositories requires discipline anyways. Either be mindful if you change your branch history, avoid it altogether or face the consequences.

 

Yes, you are entirely right. This becomes even more important when you work on group projects!

 

Thanks a lot, very clear and on point.