539

What's the difference between git merge and git rebase?

Elrond_EGLDer
  • 47,430
  • 25
  • 189
  • 180
Daniel Peñalba
  • 27,557
  • 31
  • 124
  • 209
  • 14
    since my answer was deleted, visit this link to get the right answer for this question: http://git-scm.com/book/en/Git-Branching-Rebasing#The-Basic-Rebase – laplasz Oct 01 '13 at 07:18
  • 6
    By the way i will add this site. All you need to know about git learn by playing: http://pcottle.github.io/learnGitBranching/ – Rollyng Nov 07 '13 at 15:44
  • Read this first: http://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging Then: http://git-scm.com/book/en/v2/Git-Branching-Rebasing You'll really understand. – Liber Nov 19 '14 at 02:33
  • [version control - When do you use git rebase instead of git merge? - Stack Overflow](https://stackoverflow.com/questions/804115/when-do-you-use-git-rebase-instead-of-git-merge) – user202729 Aug 14 '18 at 14:32

8 Answers8

917

Suppose originally there were 3 commits, A,B,C:

A-B-C

Then developer Dan created commit D, and developer Ed created commit E:

A-B-C-D-E

Obviously, this conflict should be resolved somehow. For this, there are 2 ways:

MERGE:

A-B-C-D-E-M

Both commits D and E are still here, but we create merge commit M that inherits changes from both D and E. However, this creates diamond shape, which many people find very confusing.

REBASE:

A-B-C-D-E-R

We create commit R, which actual file content is identical to that of merge commit M above. But, we get rid of commit E, like it never existed (denoted by dots - vanishing line). Because of this obliteration, E should be local to developer Ed and should have never been pushed to any other repository. Advantage of rebase is that diamond shape is avoided, and history stays nice straight line - most developers love that!

mvp
  • 94,368
  • 12
  • 106
  • 137
  • 65
    Nice illustrations. However, I do not fully agree with the positive tone that rebase is handled. In both merge and rebase conflicts can occur that need manual resolution. And as always when programmers are involved there is a non-neglectable chance of errors aka bugs. If a merge error happens the whole team or community can see the merge and verify whether a bug was introduced there. The history of the rebase stays in 1 developer's repo and even there it has only limited lifetime in the reflog. It might look nicer, but nobody else can see as easily what went wrong. – Uwe Geuder Sep 23 '13 at 12:59
  • 4
    > "However, this creates diamond shape, which many people find very confusing." Um...can you elaborate? – Greg Maletic Jul 03 '14 at 20:07
  • @GregMaletic: Diamond shape is non-linear history. I don't know about you, but I do not like non-linear things in general. That said, you are welcome to use merge with diamonds if you really prefer it - nobody is forcing you. – mvp Jul 03 '14 at 20:43
  • 3
    While this answer is extremely helpful, it would be better if you added actual git commands with simple foo.txt files to reproduce it locally. Like last user said, it's not obvious who's doing rebase. – Vortex Feb 26 '17 at 02:51
  • @Vortex: the whole idea is to give you explanation of the concept. Adding any git commands would just obscure what's really happening. – mvp Feb 26 '17 at 03:00
  • Perhaps a better comparison is `git merge --squash` and `git rebase`, which both try to create a history that shows code that actually existed in a single place together. Git merge (or pull) will interleave commits by date, looking like certain commits existed together (when there is no way to tell if they ever did) and implying the code at any date actually works together (there is no such implication nor is it often true). IMO `git merge` no `--squash` should never be used, it comes just short of creating lies that only the most circumspect engineer can see through. – pferrel Jan 23 '19 at 00:56
  • 1
    @pferrel: l don't think you got it correctly. `git merge` does not interleave commits (but it might appear so by looking at `git log`). Instead, `git merge` keeps both development histories by Dan and Ed preserved intact, as it was seen from each one point of view at a time. `git rebase` makes it look like that Dan worked on it first, and Ed followed him. In both cases (merge and rebase), actual resultant file tree is absolutely identical. – mvp Jan 23 '19 at 07:35
  • @mvp, You explanation doesn't explain why Git keep Dan's commit and not Ed's. – ATL_DEV Nov 15 '19 at 23:00
  • @ATL_DEV: both commits are kept in history. If rebase was done by Ed, then history would appear D first, E second. If Dan was doing rebase, it would be E then D. But, regardless of order, final state is exactly the same, and is equivalent to merge. For merge, both points of view are kept intact, and it is impossible to say which one was done first. – mvp Nov 16 '19 at 04:30
  • @mvp. Git rebase operation appears to be superfluous. If the only real difference is cosmetic, then whether it's a straight or not should really be determined in how it is visually rendered on the screen. In a sense, it's like directories in a file system which are only useful for human organization, but serves no purpose in the actual file structure implementation. – ATL_DEV Nov 16 '19 at 18:08
  • @ATL_DEV: it's not just cosmetic. Because merge keeps both development histories intact, it makes harder for people to understand what's going on. Rebase linearizes this natural conflict on who was there first. – mvp Nov 16 '19 at 18:28
  • @mvp, just to be clear, I don't see why it should linearize the conflicts at the repo level when it can keep always keep the histories intact but linearize the tree only when it presents the tree visually. – ATL_DEV Nov 16 '19 at 22:04
  • @mvp, in your answer you said "for git rebase, ...we get rid of commit E, like it never existed (denoted by dots - vanishing line)", but in your reply to "ATL_DEV", you said "for git rebase, ...both commits are kept in history...". I'm confused here: for git rebase, if "both commits are kept in history", did you really "get rid of commit E, like it never existed"? where can you see the history of commit E? – gangmax Nov 18 '20 at 01:54
  • @gangmax, commit E is removed by rebase, but changes intended by that comment live on in R. Difference between R and D is the same as difference between E and C. For merge, commit E is fully preserved in history, but that history becomes forked, which could make it more difficult to understand what's really going on. – mvp Nov 18 '20 at 16:41
  • @mvp, thank you for the detailed explanation. – gangmax Feb 07 '21 at 10:54
171

I really love this excerpt from 10 Things I hate about git (it gives a short explanation for rebase in its second example):

3. Crappy documentation

The man pages are one almighty “f*** you”1. They describe the commands from the perspective of a computer scientist, not a user. Case in point:

git-push – Update remote refs along with associated objects

Here’s a description for humans:

git-push – Upload changes from your local repository into a remote repository

Update, another example: (thanks cgd)

git-rebase – Forward-port local commits to the updated upstream head

Translation:

git-rebase – Sequentially regenerate a series of commits so they can be 
             applied directly to the head node

And then we have

git-merge - Join two or more development histories together

which is a good description.


1. uncensored in the original

Karim
  • 17,557
  • 13
  • 57
  • 68
mvw
  • 4,845
  • 1
  • 23
  • 32
  • 3
    The problem isn't language or whether the user is a computer scientist or not. While rewording it in another way helps clarify the ends (ie. what happens), it fails at explaining the means (how it happens). Git requires understanding the means in order to understand the ends. It is precisely understanding the means which makes Git so difficult. As a tool, something used to simplify or reduce the effort required in task, Git fails horribly. Sadly, too many devs fail to realize it. – ATL_DEV Nov 15 '19 at 23:10
151

Personally I don't find the standard diagramming technique very helpful - the arrows always seem to point the wrong way for me. (They generally point towards the "parent" of each commit, which ends up being backwards in time, which is weird).

To explain it in words:

  • When you rebase your branch onto their branch, you tell Git to make it look as though you checked out their branch cleanly, then did all your work starting from there. That makes a clean, conceptually simple package of changes that someone can review. You can repeat this process again when there are new changes on their branch, and you will always end up with a clean set of changes "on the tip" of their branch.
  • When you merge their branch into your branch, you tie the two branch histories together at this point. If you do this again later with more changes, you begin to create an interleaved thread of histories: some of their changes, some of my changes, some of their changes. Some people find this messy or undesirable.

For reasons I don't understand, GUI tools for Git have never made much of an effort to present merge histories more cleanly, abstracting out the individual merges. So if you want a "clean history", you need to use rebase.

I seem to recall having read blog posts from programmers who only use rebase and others that never use rebase.

Example

I'll try explaining this with a just-words example. Let's say other people on your project are working on the user interface, and you're writing documentation. Without rebase, your history might look something like:

Write tutorial
Merge remote-tracking branch 'origin/master' into fixdocs
Bigger buttons
Drop down list
Extend README
Merge remote-tracking branch 'origin/master' into fixdocs
Make window larger
Fix a mistake in howto.md

That is, merges and UI commits in the middle of your documentation commits.

If you rebased your code onto master instead of merging it, it would look like this:

Write tutorial
Extend README
Fix a mistake in howto.md
Bigger buttons
Drop down list
Make window larger

All of your commits are at the top (newest), followed by the rest of the master branch.

(Disclaimer: I'm the author of the "10 things I hate about Git" post referred to in another answer)

Steve Bennett
  • 84,226
  • 27
  • 133
  • 175
47

While the accepted and most upvoted answer is great, I additionally find it useful trying to explain the difference only by words:

merge

  • “okay, we got two differently developed states of our repository. Let's merge them together. Two parents, one resulting child.”

rebase

  • “Give the changes of the main branch (whatever its name) to my feature branch. Do so by pretending my feature work started later, in fact on the current state of the main branch.”
  • “Rewrite the history of my changes to reflect that.” (need to force-push them, because normally versioning is all about not tampering with given history)
  • “Likely —if the changes I raked in have little to do with my work— history actually won't change much, if I look at my commits diff by diff (you may also think of ‘patches’).“

summary: When possible, rebase is almost always better. Making re-integration into the main branch easier.

Because? ➝ your feature work can be presented as one big ‘patch file’ (aka diff) in respect to the main branch, not having to ‘explain’ multiple parents: At least two, coming from one merge, but likely many more, if there were several merges. Unlike merges, multiple rebases do not add up. (another big plus)

dokaspar
  • 6,795
  • 14
  • 59
  • 87
Frank Nocke
  • 7,493
  • 3
  • 58
  • 89
24

Git rebase is closer to a merge. The difference in rebase is:

  • the local commits are removed temporally from the branch.
  • run the git pull
  • insert again all your local commits.

So that means that all your local commits are moved to the end, after all the remote commits. If you have a merge conflict, you have to solve it too.

Willem Franco
  • 686
  • 6
  • 6
10

For easy understand can see my figure.

Rebase will change commit hash, so that if you want to avoid much of conflict, just use rebase when that branch is done/complete as stable.

enter image description here

Nhan Cao
  • 2,256
  • 1
  • 15
  • 12
2

I found one really interesting article on git rebase vs merge, thought of sharing it here

  • If you want to see the history completely same as it happened, you should use merge. Merge preserves history whereas rebase rewrites it.
  • Merging adds a new commit to your history
  • Rebasing is better to streamline a complex history, you are able to change the commit history by interactive rebase.
nagendra547
  • 3,469
  • 21
  • 33
1

Side by side illustration of merge vs rebase

Pay attention to the updated hashes for C5 and C6 in the rebase scenario above.

For full details and animations on the topic, I've written a separate piece on it: https://betterprogramming.pub/differences-between-git-merge-and-rebase-and-why-you-should-care-ae41d96237b6

Yatin
  • 2,348
  • 6
  • 20
  • 38