When do you use Git rebase instead of Git merge?

652,796

Solution 1

Short Version

  • Merge takes all the changes in one branch and merges them into another branch in one commit.
  • Rebase says I want the point at which I branched to move to a new starting point

So when do you use either one?

Merge

  • Let's say you have created a branch for the purpose of developing a single feature. When you want to bring those changes back to master, you probably want merge (you don't care about maintaining all of the interim commits).

Rebase

  • A second scenario would be if you started doing some development and then another developer made an unrelated change. You probably want to pull and then rebase to base your changes from the current version from the repository.

Solution 2

It's simple. With rebase you say to use another branch as the new base for your work.

If you have, for example, a branch master, you create a branch to implement a new feature, and say you name it cool-feature, of course, the master branch is the base for your new feature.

Now, at a certain point, you want to add the new feature you implemented in the master branch. You could just switch to master and merge the cool-feature branch:

$ git checkout master
$ git merge cool-feature

But this way a new dummy commit is added. If you want to avoid spaghetti-history you can rebase:

$ git checkout cool-feature
$ git rebase master

And then merge it in master:

$ git checkout master
$ git merge cool-feature

This time, since the topic branch has the same commits of master plus the commits with the new feature, the merge will be just a fast-forward.

Solution 3

TL;DR

If you have any doubt, use merge.

Short Answer

The only differences between a rebase and a merge are:

  • The resulting tree structure of the history (generally only noticeable when looking at a commit graph) is different (one will have branches, the other won't).
  • Merge will generally create an extra commit (e.g. node in the tree).
  • Merge and rebase will handle conflicts differently. Rebase will present conflicts one commit at a time where merge will present them all at once.

So the short answer is to pick rebase or merge based on what you want your history to look like.

Long Answer

There are a few factors you should consider when choosing which operation to use.

Is the branch you are getting changes from shared with other developers outside your team (e.g. open source, public)?

If so, don't rebase. Rebase destroys the branch and those developers will have broken/inconsistent repositories unless they use git pull --rebase. This is a good way to upset other developers quickly.

How skilled is your development team?

Rebase is a destructive operation. That means, if you do not apply it correctly, you could lose committed work and/or break the consistency of other developer's repositories.

I've worked on teams where the developers all came from a time when companies could afford dedicated staff to deal with branching and merging. Those developers don't know much about Git and don't want to know much. In these teams I wouldn't risk recommending rebasing for any reason.

Does the branch itself represent useful information

Some teams use the branch-per-feature model where each branch represents a feature (or bugfix, or sub-feature, etc.) In this model the branch helps identify sets of related commits. For example, one can quickly revert a feature by reverting the merge of that branch (to be fair, this is a rare operation). Or diff a feature by comparing two branches (more common). Rebase would destroy the branch and this would not be straightforward.

I've also worked on teams that used the branch-per-developer model (we've all been there). In this case the branch itself doesn't convey any additional information (the commit already has the author). There would be no harm in rebasing.

Might you want to revert the merge for any reason?

Reverting (as in undoing) a rebase is considerably difficult and/or impossible (if the rebase had conflicts) compared to reverting a merge. If you think there is a chance you will want to revert then use merge.

Do you work on a team? If so, are you willing to take an all or nothing approach on this branch?

Rebase operations need to be pulled with a corresponding git pull --rebase. If you are working by yourself you may be able to remember which you should use at the appropriate time. If you are working on a team this will be very difficult to coordinate. This is why most rebase workflows recommend using rebase for all merges (and git pull --rebase for all pulls).

Common Myths

Merge destroys history (squashes commits)

Assuming you have the following merge:

    B -- C
   /      \
  A--------D

Some people will state that the merge "destroys" the commit history because if you were to look at the log of only the master branch (A -- D) you would miss the important commit messages contained in B and C.

If this were true we wouldn't have questions like this. Basically, you will see B and C unless you explicitly ask not to see them (using --first-parent). This is very easy to try for yourself.

Rebase allows for safer/simpler merges

The two approaches merge differently, but it is not clear that one is always better than the other and it may depend on the developer workflow. For example, if a developer tends to commit regularly (e.g. maybe they commit twice a day as they transition from work to home) then there could be a lot of commits for a given branch. Many of those commits might not look anything like the final product (I tend to refactor my approach once or twice per feature). If someone else was working on a related area of code and they tried to rebase my changes it could be a fairly tedious operation.

Rebase is cooler / sexier / more professional

If you like to alias rm to rm -rf to "save time" then maybe rebase is for you.

My Two Cents

I always think that someday I will come across a scenario where Git rebase is the awesome tool that solves the problem. Much like I think I will come across a scenario where Git reflog is an awesome tool that solves my problem. I have worked with Git for over five years now. It hasn't happened.

Messy histories have never really been a problem for me. I don't ever just read my commit history like an exciting novel. A majority of the time I need a history I am going to use Git blame or Git bisect anyway. In that case, having the merge commit is actually useful to me, because if the merge introduced the issue, that is meaningful information to me.

Update (4/2017)

I feel obligated to mention that I have personally softened on using rebase although my general advice still stands. I have recently been interacting a lot with the Angular 2 Material project. They have used rebase to keep a very clean commit history. This has allowed me to very easily see what commit fixed a given defect and whether or not that commit was included in a release. It serves as a great example of using rebase correctly.

Solution 4

To complement my own answer mentioned by TSamper,

  • a rebase is quite often a good idea to do before a merge, because the idea is that you integrate in your branch Y the work of the branch B upon which you will merge.
    But again, before merging, you resolve any conflict in your branch (i.e.: "rebase", as in "replay my work in my branch starting from a recent point from the branch B).
    If done correctly, the subsequent merge from your branch to branch B can be fast-forward.

  • a merge directly impacts the destination branch B, which means the merges better be trivial, otherwise that branch B can be long to get back to a stable state (time for you solve all the conflicts)


the point of merging after a rebase?

In the case that I describe, I rebase B onto my branch, just to have the opportunity to replay my work from a more recent point from B, but while staying into my branch.
In this case, a merge is still needed to bring my "replayed" work onto B.

The other scenario (described in Git Ready for instance), is to bring your work directly in B through a rebase (which does conserve all your nice commits, or even give you the opportunity to re-order them through an interactive rebase).
In that case (where you rebase while being in the B branch), you are right: no further merge is needed:

A Git tree at default when we have not merged nor rebased

rebase1

we get by rebasing:

rebase3

That second scenario is all about: how do I get new-feature back into master.

My point, by describing the first rebase scenario, is to remind everyone that a rebase can also be used as a preliminary step to that (that being "get new-feature back into master").
You can use rebase to first bring master "in" the new-feature branch: the rebase will replay new-feature commits from the HEAD master, but still in the new-feature branch, effectively moving your branch starting point from an old master commit to HEAD-master.
That allows you to resolve any conflicts in your branch (meaning, in isolation, while allowing master to continue to evolve in parallel if your conflict resolution stage takes too long).
Then you can switch to master and merge new-feature (or rebase new-feature onto master if you want to preserve commits done in your new-feature branch).

So:

  • "rebase vs. merge" can be viewed as two ways to import a work on, say, master.
  • But "rebase then merge" can be a valid workflow to first resolve conflict in isolation, then bring back your work.

Solution 5

A lot of answers here say that merging turns all your commits into one, and therefore suggest to use rebase to preserve your commits. This is incorrect. And a bad idea if you have pushed your commits already.

Merge does not obliterate your commits. Merge preserves history! (just look at gitk) Rebase rewrites history, which is a Bad Thing after you've pushed it.

Use merge -- not rebase whenever you've already pushed.

Here is Linus' (author of Git) take on it (now hosted on my own blog, as recovered by the Wayback Machine). It's a really good read.

Or you can read my own version of the same idea below.

Rebasing a branch on master:

  • provides an incorrect idea of how commits were created
  • pollutes master with a bunch of intermediate commits that may not have been well tested
  • could actually introduce build breaks on these intermediate commits because of changes that were made to master between when the original topic branch was created and when it was rebased.
  • makes finding good places in master to checkout difficult.
  • Causes the timestamps on commits to not align with their chronological order in the tree. So you would see that commit A precedes commit B in master, but commit B was authored first. (What?!)
  • Produces more conflicts, because individual commits in the topic branch can each involve merge conflicts which must be individually resolved (further lying in history about what happened in each commit).
  • is a rewrite of history. If the branch being rebased has been pushed anywhere (shared with anyone other than yourself) then you've screwed up everyone else who has that branch since you've rewritten history.

In contrast, merging a topic branch into master:

  • preserves history of where topic branches were created, including any merges from master to the topic branch to help keep it current. You really get an accurate idea of what code the developer was working with when they were building.
  • master is a branch made up mostly of merges, and each of those merge commits are typically 'good points' in history that are safe to check out, because that's where the topic branch was ready to be integrated.
  • all the individual commits of the topic branch are preserved, including the fact that they were in a topic branch, so isolating those changes is natural and you can drill in where required.
  • merge conflicts only have to be resolved once (at the point of the merge), so intermediate commit changes made in the topic branch don't have to be resolved independently.
  • can be done multiple times smoothly. If you integrate your topic branch to master periodically, folks can keep building on the topic branch, and it can keep being merged independently.
Share:
652,796
Roman
Author by

Roman

Updated on July 08, 2022

Comments

  • Roman
    Roman almost 2 years

    When is it recommended to use Git rebase vs. Git merge?

    Do I still need to merge after a successful rebase?

    • a_h
      a_h about 15 years
    • Michael Durrant
      Michael Durrant about 11 years
      This may also help with the bigger picture: stackoverflow.com/a/9204499/631619
    • stackexchanger
      stackexchanger over 8 years
    • static_rtti
      static_rtti over 8 years
      One problem with people who like to use rebase is that it deters them from pushing their code regularly. So wanting clean history prevents them from sharing their code, which I think is more important.
    • juzzlin
      juzzlin over 8 years
      @static_rtti: That's just not true. You're using a rebase-based flow wrong if it prevents you from pushing your changes regularly.
    • Channa
      Channa almost 4 years
    • Matt
      Matt over 3 years
      My heuristic: "Try rebase, if it dissolves into conflict resolution hell give up and merge master into your branch and move on." - more detail in my post timwise.co.uk/2019/10/14/merge-vs-rebase (in the context of commercial development)
    • NotoriousPyro
      NotoriousPyro about 2 years
      Rebased method requires pushing changes more frequently instead of sitting on code that becomes unmergeable which often occurs with merge based strategies. Merging master into your branch is the worst thing to do if you're using a rebase strategy.
  • Roman
    Roman about 15 years
    By the sound of your answer, it almost seems that one must still merge even after a rebase. If I have a master branch, and a master-feature branch. I will create a feature in master-feature, then want to have that feature available in master. If I rebase, it'll take all say, N commits I made in master-feature and show the history in master. What's the point of merging after a rebase?
  • obecalp
    obecalp about 15 years
    merge after rebase is a trivial fast forward without having to resolve conflicts.
  • VonC
    VonC about 15 years
    @obelcap: Indeed, this is kind of the idea: you take all the problem-conflict in your environment (rebase master within your new-feature branch), and then co master, merge new-feature: 1 pico-second (fast-forward) if master had no evolutions
  • Sean Schofield
    Sean Schofield over 14 years
    Rebase is also nice because once you do eventually merge your stuff back into master (which is trivial as already described) you have it sitting at the "top" of your commit history. On bigger projects where features may be written but merged several weeks later, you don't want to just merge them into the master because they get "stuffed" into the master way back in the history. Personally I like being able to do git log and see that recent feature right at the "top." Note the commit dates are preserved - rebase doesn't change that information.
  • Joe
    Joe over 12 years
    So mentally, is a rebase saying: I'm now making this change to README after the new feature was implemented, as opposed to in parallel and then trivially merging that new feature with my change?
  • VonC
    VonC over 12 years
    @Joe: mentally, you are saying "replay any of my changes (done in isolation in my private branch) on top of that other branch, but leave me in my private branch once the rebase is done". That is a good opportunity to clean-up the local history, avoiding "checkpoint commits", broken bisect and incorrect blame results. See "Git workflow": sandofsky.com/blog/git-workflow.html
  • Joe
    Joe over 12 years
    @VonC: Ok thanks. Could there ever be a case where two people rebased each other's changes such that you now have two repos with two different order of commits? Would that cause them to be incompatible?
  • VonC
    VonC over 12 years
    @Joe: yes but it is bad practice to rebase what has already been pushed, or what has been fetched. So in practice, no that shouldn't be the case.
  • Joe
    Joe over 12 years
    @VonC: thought that might be the case. What worries me though is marking something as "bad practice" is usually never strong enough to keep people from doing such destructive things.
  • VonC
    VonC over 12 years
    @Joe: sure, but a/ it is rarely a "destructive" thing (you have the reflog to keep track of unreferenced commits), b/ the section "RECOVERING FROM UPSTREAM REBASE" from the git rebase man page details a possible solution in those rare instance.
  • mbx
    mbx almost 12 years
    A merge with master could result in a fast forward. In a feature branch there may be some commits, which have minor bugs or dont't even compile. If you do only unit testing in a feature branch, some errors in integration my slip through. Before merging with master, integration tests are required and can show some bugs. If these are fixed, the feature could be integrated. As you don't wish to commit buggy code to master, a rebase seems neccessary in order to prevent an all-commits-fast-forward.
  • Yugal Jindle
    Yugal Jindle almost 12 years
    Last line did it all : But "rebase then merge" can be a valid workflow to first resolve conflict in isolation, then bring back your work.
  • Scott Coates
    Scott Coates over 11 years
    @VonC "That allows you to resolve any conflicts in your branch (meaning, in isolation, while allowing master to continue to evolve in parallel if your conflict resolution stage takes too long)." The same is true with a merge though, right?
  • VonC
    VonC over 11 years
    @scoarescoare yes, but I prefer replaying my work (rebase) on top of the destination branch (for instance master) rather than merging master and potentially making some fixes to my feature branch before merging it back to master: the history is cleaner.
  • spaaarky21
    spaaarky21 over 11 years
    @Rob mentioned maintaining interim commits when merging. I believe by default merging branch B (a feature branch you've been working on) into branch M (the master branch) will create one commit in M for each commit that was made in B since the two diverged. But if you merge using the --squash option, all of the commits made on branch B will be "lumped together" and merged as a single commit on branch M, keeping the log on your master branch nice and clean. Squashing is probably what you want if you have numerous developers working independently and merging back into master.
  • Scott Coates
    Scott Coates over 11 years
    @VonC I agree that rebasing produces a cleaner history but I need help understanding how rebasing allows one to resolve conflicts in a feature branch any better/different than simply merging? I'm still learning, thanks.
  • VonC
    VonC over 11 years
    @scoarescoare the key is to see how you local changes are compatible on top of the latest upstream branch. If one of your commit introduces a conflict, you will see it right away. A merge introduce only one (merged) commit, which might trigger many conflict without an easy way to see which one, amongst your own local commits, did add said conflict. So in addition to a cleaner history, you get a more precise view of the changes you introduce, commit by commit (replayed by the rebase), as opposed to all the changes introduced by the upstream branch (dumped into one single merge).
  • ATL_DEV
    ATL_DEV about 11 years
    @Rob, your rebase explanation can use a little more explanation for people who don't have the concept of rebase down. Spaaarky21 just added some subtly to the whole thing with "squashing."
  • jpeskin
    jpeskin almost 11 years
    I believe @spaaarky21's assumption about merging is not correct. If you merge a branch B into the master M, there will be only a single commit on M (even if B has multiple commits), regardless of whether you use a plain or --squash merge. What --squash will do is eliminate the reference to B as a parent. A good visualization is here: syntevo.com/smartgithg/howtos.html?page=workflows.merge
  • spaaarky21
    spaaarky21 almost 11 years
    @jpeskin That's not what I'm seeing. I just did a quick test to verify. Create a directory with a text file, init a new repo, add the file and commit. Checkout a new feature branch (checkout -b feature.) Change the text file, commit and repeat so that there are two new commits on the feature branch. Then checkout master and merge feature. In log, I see my initial commit on master, followed by the two that were merged from feature. If you merge --squash feature, feature is merged into master but not committed, so the only new commit on master will be the one you make yourself.
  • jpeskin
    jpeskin almost 11 years
    @spaaarky21 It looks like we're both half right. When a fast-forward merge is possible (as in your example), git will default to including all commits in the feature branch B (or as you suggest, you can use --squash to combine into a single commit). But in the case where there are two divergent branches M and B that you are merging, git will not include all of the individual commits from branch B if merged into M (whether or not you use --squash).
  • Incerteza
    Incerteza almost 10 years
    but this way a new dummy commit is added, if you want to avoid spaghetti-history - how is it bad?
  • Aldo 'xoen' Giambelluca
    Aldo 'xoen' Giambelluca almost 10 years
    Hi @Alex, it depends on personal preferences and the branches protocols for your project. If you want to have these commits in your history for future reference (e.g. Did we merge master into release before the deploy?) go for a merge, otherwise if you prefer a cleaner history use rebase.
  • Aldo 'xoen' Giambelluca
    Aldo 'xoen' Giambelluca almost 10 years
    Also, the --no-ff flag of merge is very very useful.
  • Bitcoin Cash - ADA enthusiast
    Bitcoin Cash - ADA enthusiast over 9 years
    Also, git merge has the "--no-ff" (no fast-forward) option that allows you to revert all the changes introduced by a certain merge really easily.
  • honzajde
    honzajde about 9 years
    Just ti make it more clear: You refer to the situation 'whenever you've already pushed' -- this should be bold. The Link to Linus post is great, btw., clarifies it.
  • Andrew Arnott
    Andrew Arnott about 9 years
    @user271996 The second sentence in my answer is precisely that point, and it is already bolded. What more were you asking for?
  • honzajde
    honzajde about 9 years
    Sorry for not very clear comment:). While I was reading, it was not apparent if ur refering to the original broader question or your particular narrowing of it. Thats all I wanted to point to. Although my view might be subjective. Thats all
  • Croad Langshan
    Croad Langshan about 9 years
    I found this explanation surprising since if you've just ensured (through rebasing) that your git pull will be a fast-forward, at the end of the day git pull is just another way of putting a hash in a text file -- resetting -- which is a task you can accomplish using various commands (e.g. git rebase, git reset, shell redirection even), all of which are strictly equivalent. So in a sense there is no such thing as "rebase then pull", but only "rebase and reset". I guess a lot of people use pull a lot and so find that an easy way to understand this, which is fine!
  • Aldo 'xoen' Giambelluca
    Aldo 'xoen' Giambelluca about 9 years
    Yes @s4nk, rebase can rewrite the history and that's bad when other developers are working on a branch. That's why 99% of the times you rebase the commits in your "personal" branch on the top of the commits in the master branch.
  • ProblemsOfSumit
    ProblemsOfSumit over 8 years
    but isn't it best practice to "update" from master into your topic branch, before you merge the topic branch into master via PR (to resolve conflicts in your branch, not the master)? We're doing it like that so most topic branches have as a last commit "merge branch master into topic-..." but here this is listed as a "feature" of rebasing and nobody mentions it for merging... ?
  • Andrew Arnott
    Andrew Arnott over 8 years
    @Sumit: while you certainly can do that, I wouldn't call it a best practice as much as something to be avoided. Most topic branches should be able to merge without conflicts into their target branches (or else you may be doing something else wrong in your workflow). So an extra merge commit besides the PR merge is just noise. It also doesn't guarantee there won't be more conflicts by the time the PR is merged due to more changes in the target branch during the review of your PR. So I only push a merge from master to topic if conflicts actually showed up.
  • ProblemsOfSumit
    ProblemsOfSumit over 8 years
    @AndrewArnott "Most topic branches should be able to merge without conflicts into their target branches" How should that be possible when 20 devs are working on 30 branches? There will be merges while you're working on yours - so of course you have to update you topic branch from target before creating a PR... no?
  • Andrew Arnott
    Andrew Arnott over 8 years
    Not usually, @Sumit. Git can merge either direction just fine even though changes have been made to either or both branches. Only when the same lines of code (or very close) are modified across two branches will you get conflicts. If that happens frequently on any team, the team should rethink how they distribute work since resolving conflicts is a tax and slows them down.
  • Adrien Be
    Adrien Be about 8 years
    @アレックス as user Sean Schofield puts it in a comment: "Rebase is also nice because once u do eventually merge ur stuff back into master (which is trivial as already described) you have it sitting at the "top" of ur commit history. On bigger projects where features may be written but merged several weeks later, you don't want to just merge them into the master because they get "stuffed" into the master way back in the history. Personally I like being able to do git log and see that recent feature right at the "top." Note the commit dates are preserved - rebase doesn't change that information. "
  • Aldo 'xoen' Giambelluca
    Aldo 'xoen' Giambelluca about 8 years
    @AdrienBe it is a very good point and one of the reasons why I like to rebase - history looks much tidier ;)
  • kellyfj
    kellyfj about 8 years
    Merges do not combine commits - that would be rewriting history. Rebase does that.
  • MarkSwears
    MarkSwears about 8 years
    Why is that the "(you don't care about maintaining all of the interim commits)" aside still in this answer? It made no sense in '09 and it makes no sense now. Also, surely you would only want to rebase if another developer made related changes that you needed - if they made unrelated changes, your feature branch should merge easily without conflicts anyway, and your history would be maintened.
  • Roy Tinker
    Roy Tinker over 7 years
    I think it bears repeating here -- remember that all these terms (merge, rebase, fast-forward, etc.) are referring to specific manipulations of a directed acyclic graph. They become easier to reason about with that mental model in mind.
  • Aldo 'xoen' Giambelluca
    Aldo 'xoen' Giambelluca almost 7 years
    @RoyTinker good point. For some weird reasons although I know repos are trees (as you pointed out), I find much easier to think in terms of "sets of changes" :)
  • Gavin S. Yancey
    Gavin S. Yancey almost 7 years
    @mbx git merge supports the --no-ff option which forces it to make a merge commit.
  • N Sharma
    N Sharma almost 7 years
    "if you started doing some development and then another developer made an unrelated change"- Do you mean another developer made changes and commited code in the master branch and to have that code in the branch which was created to add single feature ?
  • Marnen Laibow-Koser
    Marnen Laibow-Koser almost 6 years
    @Aldo There's nothing "clean" or "tidy" about a rebased history. It's generally filthy and IMHO awful because you have no idea what really went on. The "cleanest" Git history is the one that actually occurred. :)
  • Marnen Laibow-Koser
    Marnen Laibow-Koser almost 6 years
    I mostly love this answer. But: Rebase doesn't make a "clean" history. It makes a more linear history, but that's not the same thing at all, since who knows now much "dirt" each commit is hiding? The cleanest, clearest Git history is the one that keeps branch and commit integrity.
  • Marnen Laibow-Koser
    Marnen Laibow-Koser almost 6 years
    @AndrewArnott If master has changed, I think the extra merge that Sumit is recommending is a good idea. You’re right that the code will come out the same either way, but that doesn’t take into account the fact that if master is changed, I have to test that my feature branch still works. The easiest way to do that is to merge master into the feature branch, test, and make any necessary changes till the feature branch is correct, and then merge it into master. Sure, it may generate an extra merge commit, but so what?
  • pkamb
    pkamb about 5 years
    You shouldn't be afraid, in general, of overwriting a pushed remote branch. Just don't rewrite the history of your team's long running branches such as master and dev. Nothing wrong with rebasing some random feature branch. Or, rebase locally and then push to a new feature branch which you then use to create the PR.
  • Marnen Laibow-Koser
    Marnen Laibow-Koser almost 5 years
    @benjaminhull Thanks!—except I hope my answer is fact-based. IMHO opinion has little place in this sort of thing: it's a fact that losing your actual history makes life harder later.
  • surfrider
    surfrider over 4 years
    Agree. Merge will never lead to corrupted history etc. (when you rebase your pushed commits)
  • Fahmi
    Fahmi about 4 years
    @jpeskin I'm using v2.25.1 and confused. This is what I did. I created branch foo, added one commit on master and multiple commits on foo then git merge foo. If I view log it shows all of the commits from foo. It contradicts way you said "git will not include all of the individual commits from branch B if merged into M" ...
  • Nico Haase
    Nico Haase almost 4 years
    Can you explain some points further? How does rebasing my own branch on master pollute master with any commit?
  • Andrew Arnott
    Andrew Arnott almost 4 years
    @NicoHaase Rebasing multiple commits onto master would only be advisable IMO if you had validated each commit as a good, tested change. Otherwise you "pollute" master with a bunch of commits that are not appropriate by themselves. Using a merge commit instead would be preferable in that case since it records via git history that a topic branch existed and suggests that it was likely only fully validated in its final form (the merge commit). If you have just one commit that you're rebasing to the tip of master, I don't see a problem with that, particularly if you do it before pushing.
  • Arefe
    Arefe almost 4 years
    @アレックス This is very bad and can bring a long history of the commits to the branch.
  • aderchox
    aderchox almost 4 years
    Your answer is very helpful but I believe making it more explicit that you're talking about "doing the rebase in the local repository" (and not on a public branch) is very much needed. Also instead of a fast-forward merge, you could also make another rebase, rebasing the master branch off of the cool-feature.
  • pkubik
    pkubik almost 4 years
    It's worth mentioning that git has recently changed it's git pull behavior to include the --rebase flag by default. That means that doing rebases on branches used by multiple developers is a little less dangerous. A person pulling your changes might be surprised that there are some conflicts to be resolved during such an operation, but there would be no disaster.
  • Argeman
    Argeman over 3 years
    It is the other way round. If you rebase, your history is rewritten and therefore some information is lost. Merge doesn't alter nor loose any history, so your points are wrong. The one most important point you miss is that the rebase means that you have a linear history. Your answer misses the point of rebasing!
  • Thierry Vilmart
    Thierry Vilmart about 3 years
    CLARIFICATION. If you are a developer used to have a trash history, then you merge and you squash. If you care about the git history, then you rebase master into your branch. And you fix manually each of your own commits that has conflicts. And you know the several git rebase --continue or --abort. Note that merge commits make the repo bigger in size over time. PLEASE, vote down the guys that say to never rebase master or mentioning the false golden rule.
  • Maf
    Maf about 3 years
    I don't know why this answer has lots of downvotes. I had to upvote to minimize the damage. LOL. I partially agree, but I think we can rebase if we're the only one working in the branch to keep everything cleaner. The main problem is if for some unexpected reason others start working on it as well.
  • rob2d
    rob2d about 3 years
    I don't think anyone was talking about rebasing when merging INTO master. So this comment is completely off, and people will not get that you rebase feature branches onto master vs master on the other branches.
  • rob2d
    rob2d about 3 years
    I'm not sure why you can't rebase on a feature branch, then merge on a public branch.
  • Nir O.
    Nir O. almost 3 years
    I would remove the downside (2) completely from your list because, as you said, squashing is a perfect solution to (2) and it always works
  • nijave
    nijave over 2 years
    Another con for rebase, imo it's harder in high-velocity git repos especially where the build time is > average time between merges. If branches are constantly being merged in, you need to keep rebasing until it's your turn which can be tricky if you're also coordinating with a build to pass. e.g. monorepos rebase merges to a shared branch might be difficult
  • crazyTech
    crazyTech over 2 years
    ( stackoverflow.com/a/804178 ) Rebase into our own dev branch,then merge into master? "You can use rebase to first bring master "in" the new-feature branch: the rebase will replay new-feature commits from the HEAD master, but still in the new-feature branch, effectively moving your branch starting point from an old master commit to HEAD-master.That allows you to resolve any conflicts in your branch (meaning, in isolation,).Then you can switch to master and merge new-feature (or rebase new-feature onto master if you want to preserve commits done in your new-feature branch)."
  • Marnen Laibow-Koser
    Marnen Laibow-Koser over 2 years
    @Thierry Huh? I care about maintaining a good, truthful history. That’s precisely why I (almost) never use rebase. Rebasing usually creates commits that represent a state of the code that never actually existed or was tested—that is, a trashy history, or rather, not a history at all. Merge commits preserve what really happened and what was developed in which context.
  • Thierry Vilmart
    Thierry Vilmart over 2 years
    Haha good one. I am an expert in git because I never use rebase! If there is a trivial change on master like documentation, I must not rebase it, I need a nice merge commit to show that I am skilled in git.
  • Marnen Laibow-Koser
    Marnen Laibow-Koser over 2 years
    @Thierry No. I mostly avoid rebase simply because it creates “fake” commits (that is, commits that represent states that were never tested), and because it makes the history harder to understand. I avoid squash (in general) because I normally want more granular commits. Therefore, I use merge commits because they do the best job of preserving the history in all parent branches.
  • Thierry Vilmart
    Thierry Vilmart over 2 years
    When you merge, you get a splash of all files at once, disregarding if you have commits for certain purposes. When you rebase master, it will stop on each commit you have made, waiting for you to make each commit clean with correct merging. I prefer the fine-grained rebasing. You are allowed to prefer a big merge at once. If master has 4 more commit causing conflits with mine, I pick master as it is, and I change my own commits one by one. Each commit is edited to solve merging problems.
  • Marnen Laibow-Koser
    Marnen Laibow-Koser over 2 years
    @Thierry When you merge with a merge commit, all the original commits are preserved, so the result is as fine-grained as rebase, but keeps each commit in its original form (no further editing needed) and context, which keeps the history meaningful. That’s why I prefer it in all cases.
  • Thierry Vilmart
    Thierry Vilmart over 2 years
    And respectfully, 99% of people do like you. I am against the Attlassian rule that define people as stupid if they do otherwise and rebase/edit 8 commits, even at job interviews during which it is a show of and nothing is detailed it becomes the standard to ban rebase. I am a Cartesian (from René Descartes), this means I have thousands of hours in maths, and among 4 principles (doubt, logic, alternatives, split) I split in small problems. The huge mega merge conflicting with 100 files in 30 commits, I split it in small parts to have clear visibility on small things, in a restricted context.
  • Marnen Laibow-Koser
    Marnen Laibow-Koser over 2 years
    @Thierry Vilmart I split a mega merge into small parts too. Those parts are called commits. (But I also try to develop smaller features so that mega merges aren’t always necessary.)
  • chetan
    chetan over 2 years
    Thanks, very useful. This highlights an important point of there being multiple merge commits that can be avoided using rebase.
  • potter1024
    potter1024 over 2 years
    The commits will be merged as a single commit if we avoid the fast-forward merge. This can easily be done by adding a flag --no-ff.
  • datWooWoo
    datWooWoo over 2 years
    It doesn't really "depend" when you can gain the same advantages of a "tidy history" without the massive disadvantages of it by simply using search / filter commands to view the history. Making rebasing practically useless.
  • tfrascaroli
    tfrascaroli about 2 years
    I'm commenting here because I have no idea where to complain about this. If I rebase main -> feature, GitHub will show the changes up to the common ancestor, which is abominable because reviewing that PR implies reviewing all of the work that has already been merged to main. It's disgusting, and that's why I use merge instead.
  • Jeehut
    Jeehut about 2 years
    @tfrascaroli I don't get your point, if you rebase your feature branch onto the latest commit of your main branch, then a PR targeting the main branch should only show the changes in the feature branch AFTER the common ancestor. What you describe is only possible if your PR is targeting yet another branch, not main. Or am I misunderstanding something?
  • tfrascaroli
    tfrascaroli about 2 years
    Well, this just happened to me yesterday. Branch feature from main. Merge other features to main with Squash and Merge. Rebase main -> feature. PR feature -> main = Impossible review because the changes detected go back to the branching from main. If I instead do Merge main -> feature and then PR feature -> main that doesn't happen.
  • Jeehut
    Jeehut about 2 years
    @tfrascaroli You say "main -> feature": Why are you rebasing your main branch onto the feature branch? You should rebase your feature branch onto the main branch instead. Also, I'm not sure what "Squash and Merge" does, but your main branches commits should never be changed. If you start a feature branch from the main, then make changes to the previous commits in the main branch (e.g. through squashing), then git has no way of solving that. The past history of main should never be changed. Then what you describe shouldn't be possible. Never happened to me in >10 years.
  • loopmode
    loopmode about 2 years
    To me, this anwer is not very helpful. The question is not about how rebase works or what it does. Instead, it's about when to use it as opposed to merge. Essentially, this answer boils down to "if you want to avoid spaghetti-history".
  • huuthang
    huuthang about 2 years
    I like this answer
  • Hassan Faghihi
    Hassan Faghihi about 2 years
    The issue I face with rebase most, Is that I always go toward the better, cause I'm not sure if it asks me again, yet, some of the better changes, may not work in the previous commit, so I'm wondering if lose the ability to rollback to those code without error. that's why when there are conflicts I rather do Merge, also when it's a long journey, but my company strictly uses rebase... also I noticed the loss of git blame, which indicates the code is written by someone else.
  • c0dezer019
    c0dezer019 almost 2 years
    I just merge. If I see that main/master has a change I'll merge it with my current branch. I've never used rebase.
  • c0dezer019
    c0dezer019 almost 2 years
    I dont see why you'd want to not track every new feature added. If anything, at least squash. This way you can at least rollback if you decide you dont need or want that feature anymore.
  • Jeehut
    Jeehut almost 2 years
    @NirO. In my experience squashing is not always possible. Imagine you have 3 commits in your feature branch: A, B, and C. Imagine A and C are changing the same line of code. But B does something entirely unrelated, so you want to keep it as a separate commit. In this simple example it would already not be easy to properly squash A and C into one commit. With more commits, it gets worse. And C might hold other changes you might want to keep, too. So I don't think I can remove the downside (2). AFAIK
  • golddragon007
    golddragon007 almost 2 years
    Rebase has way more issues. Especially when people rebases remote branches (force push (possible overwrite of somebodies work) and git branch reset on pull (you have to check whenever the remote changes were legit and not a malicious actor injected some code into the branch)). It also causes when people rebasing the target branch (continuously you have to update your own branches as it would give conflicts with the target on merge).
  • golddragon007
    golddragon007 almost 2 years
    When you move your branch to another base, and you have conflict, you lose that information, as there's no anything that tells about it (when you merge you have a commit from it, this is really good when a wrong conflict resolution caused a bug). It's possible to have duplicated commit copies if you don't rebase always the branches before merging to the target branch.
  • Jeehut
    Jeehut almost 2 years
    @golddragon007 If I understand your points correctly, you're talking about a situation where a feature branch A is opened by a developer, then another developer starts their feature branch B from A. When A gets rebased, B of course has to rebase, too. While that is true, I don't think it's a downside of the rebase itself. The issue lies in the teams way of working. There should never be the need of branching off of an actively worked on feature branch. Also, no 2 people should work on the same feature branch. They should be small and scoped to 1 devs work. IMO
  • golddragon007
    golddragon007 almost 2 years
    @Jeehut There is a need to start a branch from another feature branch, whenever you have a dependency on another ticket's feature and you can't implement it without it. Even worse if you implemented the dependency as you can't review it, but when you have many such tickets that depend on a previous one you can't wait for somebody always to merge the dependency. On top of that rebasing, the remote branch is not a good idea, once published shouldn't be altered. I also saw rebased release branches, in that case, all the merges are gone, but have fun doing a git bisect on it.
  • golddragon007
    golddragon007 almost 2 years
    All the commits look out of order, chronologically and by the possible branch (which is gone). It's all done for "clean history"; I just can't find the "history" part in it.
  • Jeehut
    Jeehut almost 2 years
    Of course you shouldn’t rebase release branches. I only talked about main branch and feature branches. And a feature branch from a feature branch should be easy to rebase onto the rebased feature branch anyways as the merge conflicts of the feature are resolved already.
  • Jeehut
    Jeehut almost 2 years
    And I want to stress the point again that feature branches should be as small as possible. According to CodeClimate documentation, the most efficient teams have a cycle time (time from first commit in a feature branch until its merge) of less than 24 hours. While each project is different, it's always a good idea to split task into small units and merge each PR fast, then you prevent dependency hell where you have to branch off of a feature branch. This helps independent of if you prefer merge or rebase.