Reputation: 31847
What's the difference between git merge
and git rebase
?
Upvotes: 681
Views: 325991
Reputation: 116038
Suppose originally there were three commits, A
,B
,C
:
Then developer Dan created commit D
, and developer Ed created commit E
:
Obviously, this conflict should be resolved somehow. For this, there are two ways:
MERGE:
Both commits D
and E
are still here, but we create a merge commit M
that inherits changes from both D
and E
. However, this creates a diamond shape, which many people find very confusing.
REBASE:
We create commit R
, whose 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 forming a vanishing line). Because of this obliteration, E
should be local to developer Ed and should have never been pushed to any other repository. The advantage of rebasing is that the diamond shape is avoided, and history stays a nice straight line - most developers love that!
Upvotes: 1052
Reputation: 1209
merge
and rebase
?Reading the official Git manual it states that “rebase reapplies commits on top of another base branch”, whereas “merge joins two or more development histories together”. In other words, the key difference between merge and rebase is that while merge
preserves history as it happened, rebase
rewrites it.
Let's contextualize these statements with a side-by-side example!
As illustrated above, the merge
operation intertwined the branches together by creating a new single merge commit (C7), causing a diamond shaped non-linear history — essentially preserving history as it happened. By comparing this result with the outcome from the rebase
action we see that no merge commit was created, instead the two commits C5 and C6 simply got rewinded and reapplied straight on top of C4, keeping the history linear.
If we scrutinise the two reapplied commits even further, we can see that the hashes have changed, indicating that rebase
truly rewrites history.
Whenever you rebase
a branch, new commits will always be generated even though the content might still be the same! That said, any former commits will eventually (post garbage collection) be deleted from history if no other pointer (branch/tag) is referencing them.
We’ve seen how rebase rewrites history, while merge preserves it. But what does this mean in a broader sense? And what possibilities and potential drawbacks do the two operations come with?
Conflicting changes
Let’s say, for example, you’ve had some nasty conflicts trying to integrate the changes. In the merge scenario, you would have only needed to solve the conflicts once, straight in the C7 commit. With rebase, on the other hand, you could potentially have been forced to solve similar conflicts in each commit (C5 and C6) as they were reapplied.
Published branches
Another potential problem related to rebase occurs when the branch you are rebasing has already been published remotely, and someone else has based their work on it. Then, your rebased branch can cause serious confusion and headaches for all involved parties as Git will tell you that your branch is both ahead and behind at the same time. If this happens, pulling remote changes using the rebase flag (git pull --rebase) generally solves the problem.
Furthermore, whenever you are rebasing an already published branch, regardless if no one else has based their work on it, you’ll still need to force push it to get your updates to the remote server — overwriting the existing remote reference completely.
Loss of data (to your advantage)
Finally, as rebase rewrites history while merge preserves it, it’s possible to actually lose data when rebasing. When new commits are reapplied, the old ones are (eventually, post garbage collection) deleted. This same trait is in fact what makes rebase so powerful — it allows you to tidy up your development history before making it publicly available!
While merge
is safe to use from a potential data loss perspective, and can feel more straight forward to use. Here are some pointers that can help you avoid the most common issues related to rebase
.
Source: Above excerpt is taken from this full length post on the subject: Differences Between Git Merge and Rebase — and Why You Should Care
Upvotes: 36
Reputation: 1177
let's say you have done 3 commits in your feature branch when you want to send your feature branch changes to the main branch. You have two options
git merge
: In this case main branch will receive only 1 commit (combining 3 commits)git rebase
: In this case main branch will receive 3 commitsUpvotes: 7
Reputation: 6302
I found one really interesting article on git rebase vs merge, thought of sharing it here
Upvotes: 6
Reputation: 2515
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.
Upvotes: 19
Reputation: 904
Git rebase is closer to a merge. The difference in rebase is:
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.
Upvotes: 36
Reputation: 10376
While the accepted and most upvoted answer is great, I additionally find it useful trying to explain the difference only by words:
merge
rebase
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)
Upvotes: 58
Reputation: 125995
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:
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.
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)
Upvotes: 222