DEV Community

Cover image for There Is No "Right" Way: Git Rebase vs Merge

There Is No "Right" Way: Git Rebase vs Merge

Molly Struve (she/her) on September 18, 2019

In honor of my new license plate, I decided I wanted to do a quick, little post on rebase vs merge, how each one works, and how I choose to use eac...
Collapse
 
simonhaisz profile image
simonhaisz

Ah, the venomous arguments about trivial things...

On this particular topic, my preference is not to rewrite public history. Rebasing a feature branch that's already on the remote seems wrong to me, so at that point I will always merge master into it. However locally I will rebase most of the time, for all the reasons you outlined here.

Which leads into my example - to squash or not to squash. I've worked with people that think every merge should have a single commit. And others that are just as adamant that you should never rewrite history and every commit should be left the way it was created.

Similar to my merge/rebase preference, I will cleanup my messy local commits by squashing them before pushing. Often I won't squash though because I think the commits are separate things and if I need to revert later on I can be more selective. But what I won't do is squash corrective commits with original commits. If I get feedback on a PR and then I incorporate it I want that history to be preserved. Bizarrely to me, there are some of the 'there shall only be one' committers' who would re-write their branch commits so that changes made after feedback would be incorporated into the same commit as their original changes. They say it's cleaner - to me it's like lying about your work.

Collapse
 
jessekphillips profile image
Jesse Phillips

The real question is what do you want to get out of your history?

To me history is the why. I like to use the example of undo trees, seen in emacs and vim, these could be view as in memory commits. They have branching and timestamps, but limited in scope to a single file.

The reality is, this isn't the history people keep. They work and craft out a spot they believe is complete. Or they adhere to someone commit twice a day rule. Either way the history is not real.

There are specific tools which make use of history. bisect which searches for a commit. blame which describes a file based on its makeup of commits. revert which is the 'undo' of git, cherry-pick the copy/paste of git. I want to build out a history which maximize the usefulness of these tools.

Git also provides the tools to help with that, staging area, commit --fixup, rebase -i, and more. Fixup is great for code reviews while allowing for quick cleanup before merging.

Yes it doesn't matter, unless your goals line up with mine.

Collapse
 
peterdavidcarter profile image
Peter David Carter • Edited

Regarding squashed changes for me the answer is simple: on larger projects squash, on smaller projects don't. Reason being is on smaller projects having the complete history right there is useful. On larger ones you'll be forced to scroll through dozens, hundreds or even thousands of commits to find even a relatively recent change. No-one wants to do that.

Collapse
 
peterdavidcarter profile image
Peter David Carter

Regarding venomous arguments over trivia seems to me there are a few reasons for this.

The first is that sometimes seeming trivia really does matter.

The second is that some devs lack empathy and can't understand other's preferences.

Following on from these, to non-techies the one can look very much like the other.

Bad devs will often argue personal points on genuine trivia because it makes things nicer for them personally, and since there are likely few real world consequences they don't have to worry about being wrong. Or they just can't tell the difference...

Good and great devs will often still argue trivia for the reason outlined: non-techies and bad devs often can't tell the difference and being seen to be knowledgeable in general can establish them in a position where they can improve the project as a whole, rather than deferring to bad or mediocre devs who would create an inferior product.

Collapse
 
molly profile image
Molly Struve (she/her)

Good call on squash or not to squash argument! That always gets our devs going at Kenna lol

Collapse
 
rranslam profile image
Rob Ranslam

The real argument is about what history is and how to preserve it. It's NOT the minutiae; It's the narrative of what the commit does when applied. So rebase -i to craft that narrative! Or git commit --amends. Remember that git is collaboration tool too.

Keeping a history littered with 'add new comment'-like goo should be squashed and never be in Master. Also, It's almost pointless to merge a single squashed commit to master.

So, If you're pro Master branch merge commits, it best to have a crystal clear rational/strategy as to why you need to keep and share that commit history as the product dev proceeds. Otherwise it's goo.

I'm for a linear history with rare merge commits.

Collapse
 
dovidweisz profile image
dovidweisz

The app I'm working on has rebasing ENFORCED!

This is achieved by blocking pushes on a subtask branch if it is behind it's feature branch. (Development is done on subbranches, testing is done on feature branches, and code review happens in the PR between the two.) Git remote actually responds with the exact commands you need to run in order to get up to speed.

This works pretty well because everyone does it, and our history is just so pretty 🙄.

My biggest beef with this is that it messes with my code review process: The way I work is I review all the code, and if I find issues I comment on them, and decline the PR. The developer then makes the necessary changes, pushes new commits and reopens the PR. At this point I don't want to review all the code. I want to review the new commits only. But since it was rebased, it's hard to find the new changes (and don't get me started on squashed commits).

The integrity of the hashes are also important in this case. It prevents people from perhaps using shortcuts that would of otherwise not been approved in the standard process.

Another issue is that when conflicts are resolved by a different developer, the commit still has the original developers name on it, Which just confuses them.

So as long as no one else involved in a branch, rebase and squash away (YOLO), but please don't enforce it.

Collapse
 
cescquintero profile image
Francisco Quintero 🇨🇴

In my initial years doing web development, something weird that used to happen to the team was that sometimes when doing git merge changes would go missing.

This caused the affected pals to be wary of git even to the point of thinking not to use it.

It wasn't until last year(Q4) that I really understood how rebasing works and why that situation happened.

So, I really agree with you that *neither rebase or merge are the right way but rebasing is the way to prevent merges that "remove" code.

How come?

Well, if two devs modify same file, same lines and Dev A pushes to master and then Dev B pulls, if it doesn't do a merge conflict git will remove Dev B changes and place Dev A ones.

I don't really recall the exact conditions for this to happen but it's something like this.

This is when rebasing comes in hand because it kind of respects the commit history and moves rebased commits to the beginning/tip.

Currently, I mostly use git merge but when I feel that situation could happen, I go with git rebase.

👍🏾👍🏾

Collapse
 
mrgung profile image
Steffen Glückselig

No way git loses commits(!) by simply merging. That only happens if Dev B hasn't commited.

Collapse
 
longthtran profile image
Long Tran • Edited

Hi Molly,

I feel excited after reading. For your opinion that rebase should be used when "feature branch needs to be updated to master" which we can make the history clean. Then there is a pathetic pain that it's really difficult for code reviewing on pull request times -- the request shall contains redundant commits from master!

Let's assume the feature branch has 3 devs working on it. My way is to assign one to hold the role for keeping that branch up to date which means he/she will fetch new commits + rebase onto master (resolving conflicts if there is) and then notify other 2 devs to stop pushing new commits in case of lost commits. Means everyone have to wait for the "forced push". In the end, the feature branch has code as expected and everyone can push, pull, fetch normally. The problem is it's painful to postpone every members in branch for just an updating. And what if the branch has a lot of participants like over 10 people, how can we solve this without "forced push"?

Collapse
 
uuykay profile image
William Kuang

Great explanation! I was actually confused reading someone else's blog on this but yours explains it perfectly! It also explains how I've never used rebase, and why I've always gotten by with git merge haha. I will take on your suggestion to use rebase when merging master back into a feature branch.

Collapse
 
aschwin profile image
Aschwin Wesselius • Edited

When you are starting out, don't look for the right way, look for the way that works best for you.

This.

So, what I get from this article, it makes sense to rebase "downstream" and merge "upstream". I like that. I will be like Molly.

And if it doesn't work, my pragmatic nature will overcome this with ease.

Very straight forward article by the way. Thank you for that.

Collapse
 
nicolaerario profile image
Nicola Erario

Very well written! Your strategy is same as the mine; also I never rebase a remote on my local branch

Collapse
 
molly profile image
Molly Struve (she/her)

Thank you! I know many others have done posts on rebasing vs merging but hopefully sharing my perspective and/or explanation will help someone understand it better!

Collapse
 
nicolaerario profile image
Nicola Erario

You can trust me: among all the merge vs rebase post, your is the only comprehensible!

Collapse
 
scottg profile image
Scott Goodwin

Can't say much about rebase -- Rebase is evil. Ok, maybe not evil, maybe it's necessary given the requirements git needs to support (huge Linux repos). But history should never be forgotten, and that's what rebase does. I've been working with Fossil and prefer it.

No flames, not trying to convert anyone -- here's a comparison of the two:

fossil-scm.org/home/doc/trunk/www/...

And an article from yesterday:

theregister.co.uk/2019/12/03/githu...

Again, not trying to convert, just showing another option.

/s.

Collapse
 
negue profile image
negue

Every time I tried rebase, it screwed up my repo

So since then I stayed on merge 😅

Collapse
 
andreasjakof profile image
Andreas Jakof

I think I finally understood rebase. 😳

Collapse
 
andreasjakof profile image
Andreas Jakof

To my defense I must add, that I am working with only for a few months now, and never had the usecase for something like rebase.

Collapse
 
booyaa profile image
Mark Sta Ana

Thank you so much for this super clear explanation! I’ve seen so many posts attempt to do this and fail. Also awesome custom license plate!

Collapse
 
gixxerblade profile image
Steve Clark 🤷‍♀️

Sweet license plate BTW 😋

Collapse
 
khatri_amol profile image
amol khatri

A

Collapse
 
chathula profile image
Chathula Sampath

Thanks for sharing this way of your working ;) grabbed many things.