git merge vs git rebase
In Git, there are two main ways to integrate changes from one branch into another: the merge
and the rebase
.
1. fast-forward vs three-way merge#
There are two type of merge:
- three-way merge,
- happens when the branches’ commit have diverged
- will result a merge commit
- fast-forward merge,
- happens when there is a liner structure in the commit history
- we usually prevent fast-forward merge, because there is no merge commit.
- can be suppressed with the
--no-ff
option
The liner structure commit structure looks like this:
A---B fixbug
/
...--E master
Branches’ diverged commit structure looks like this:
A---B fixbug
/
...--E--F master
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/zOnwgxiC0OA?autoplay=0&controls=1&end=0&loop=0&mute=0&start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
</div>
Video: https://youtu.be/zOnwgxiC0OA
2. git rebase#
The Golden Rule of Rebasing reads: “Never rebase while you’re on a public branch.”
Source: https://www.gitkraken.com/blog/golden-rule-of-rebasing-in-git
On main
branch:
* commit 41bc8e89e60d75e21e034aaabcbd20103a61fca4 (HEAD -> main)
| main: Fri 15 Sep 2023 13:01:02 ADT
|
* commit 2220b67f9c8ccf5f47e51bff7bd3a3fca6e141b6
main: Fri 15 Sep 2023 11:47:54 ADT
On fixbug
branch:
* commit 0096a2dfa2b4e4c40011213b6cce12ee73833ca9 (HEAD -> fixbug)
| fixbug: Fri 15 Sep 2023 11:48:53 ADT
|
* commit fd900fa0c05632757f45fd6fee236eb84c99bb94
| fixbug: Fri 15 Sep 2023 11:48:27 ADT
|
* commit 2220b67f9c8ccf5f47e51bff7bd3a3fca6e141b6
main: Fri 15 Sep 2023 11:47:54 AD
Now the commit history of all branches looks like this:
A---B fixbug
/
...--E---F main
Go to main
branch and make rebase.
$ git switch main
$ git rebase fixbug
Successfully rebased and updated refs/heads/main.
Check the log, you can see, these two branches combined but the commit histroy structure is linear:
* commit 918260ae4f0b7f7d573a9a640ce380ea0f861a6a (HEAD -> main)
| main: Fri 15 Sep 2023 13:01:02 ADT
|
* commit 0096a2dfa2b4e4c40011213b6cce12ee73833ca9 (fixbug)
| fixbug: Fri 15 Sep 2023 11:48:53 ADT
|
* commit fd900fa0c05632757f45fd6fee236eb84c99bb94
| fixbug: Fri 15 Sep 2023 11:48:27 ADT
|
* commit 2220b67f9c8ccf5f47e51bff7bd3a3fca6e141b6
main: Fri 15 Sep 2023 11:47:54 ADT
Now the commit history of main
branch looks like this (and you can delete fixbug
branch):
A---B---F' main
/
...--E
As you can see, rebase just make a fast-forward merge happen even the branches has diverged.
And note that the F'
mean it’s a copy of original commit F
(git will do this internally), this is why we should not use rebase on a shared branch, main
for example, because rebase
will “change” the commit history of branch main
.
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/zOnwgxiC0OA?autoplay=0&controls=1&end=0&loop=0&mute=0&start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
</div>
3. git rebase vs merge#
- Merge preserves commit history.
- Use merge on a public branch.
- Rebase rewrites (makes copy) history.
- Use rebase on a private branch to catch up update form remote.
- Why rebase rewrite commit history: https://youtu.be/zOnwgxiC0OA?si=CwbvoPI35pHgJ1pn&t=401
git push --force
on shared branches is an absolute no-no.
Note that we say use rebase on a private branch means we can use the command
git rebase master
on a private, please don’t usegit rebase fixissue
onmaster
branch which apparently is a publick branch.Learn more: https://youtu.be/zOnwgxiC0OA?si=CwbvoPI35pHgJ1pn&t=401
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/CRlGDDprdOQ?autoplay=0&controls=1&end=0&loop=0&mute=0&start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
</div>
References: