---
# System prepended metadata

title: Git Merge 與 Git Rebase 差異
tags: [Git]

---

# 前言
在Git的合併分支功能中，我們可以選擇使用`git merge`或是`git rebase`進行合併，而`git merge`的部分又可分為`non-fast-forward  merge`以及`fast-forward merge`。

這篇文章將針對Git不同的合併分支進行講解，以及差異性的比較。閱讀這篇文章前，應對於Git與分支已有基本的概念，如果有不清楚的可以先參考另外兩篇文章([Git概念以及常用指令](https://hackmd.io/@Lion-Le/SyY608E3C)、[Git Branch & Git Merge](https://hackmd.io/@Lion-Le/rJOHUpXTR))
</br>

# Git的合併分支
當接收到新需求時，工程師會以master/main分支當作基底，為新功能另開feature分支進行開發。

![feature1](https://hackmd.io/_uploads/SkQ4nB3aR.jpg)
</br>
### git merge (Non-Fast-Forward)
當工程師開發完成時，我們會需要將分支合併回master/main branch，這時我們可以先使用`git checkout main`切換回master/main分支，再使用`git merge feature`指令，將已開發完成的程式合併回主要分支。

![feature2](https://hackmd.io/_uploads/BkGvnBnp0.jpg)

最終會出現合併後的E版本。
</br>
### git merge --ff (Fast-Forward)
在<b><u>原分支(master/main)沒有新版本的前提下</u></b>，我們可以使用`git merge --ff`指令進行合併，將master/main分支整理的更單純。

同樣先使用`git checkout main`切換回master/main分支，再使用`git merge feature --ff`指令，將已開發完成的程式合併回主要分支。

![feature3](https://hackmd.io/_uploads/r19HyLhp0.jpg)

合併後的master/main分支會呈現線性的樣子，原本的feature分支會整個直接被合併回master/main分支，並且<b><u>Fast-forward不會出現合併後的E版本</u></b>，最新的提交仍為D版本。



> [!Note]
> `git merge <branchName> --ff`指令在遇到無法執行Fast-Forward合併的狀況時，會自動改回以一般的方式合併。
> 
>如果想要強制Git只能執行fast-forward合併的話，可以使用`git merge <branchName> --ff-only`指令，當遇到無法合併的狀況時，會直接以`non-zero`的狀態退出。
>
</br>

假設原分支(master/main)已有新版本的提交，就無法使用Fast-forward的方式合併分支。
![feature4](https://hackmd.io/_uploads/BJWhfLha0.jpg)

只能使用一般的方式合併
![feature5](https://hackmd.io/_uploads/r1G0QU2T0.jpg)
</br>

### git rebase 
針對原分支(master/main)已有新版本提交的狀況，我們也可以使用`git rebase`的方式進行合併，讓整個分支更簡潔。

同樣先使用`git checkout main`切換回master/main分支，再使用`git rebase feature`指令進行合併分支。
![feature6](https://hackmd.io/_uploads/rkAfK8nTC.jpg)

會以當前分支(master/main)的F版本為基底，將feature分支的Ｃ、Ｄ版本合併回當前分支(master/main)。

`git rebase`的合併，可以想像成將當前分支(master/main)的提交紀錄作為上游，將被rebase分支(feature)的提交紀錄剪下作為下游，最終將兩者合併為線性的樣子。

以結果來看，會比較像是直接修改歷史提交紀錄。
</br>

#### git rebase的原理 
`git rebase`背後所執行的操作，其實與直觀上看的剪下、貼上有些許差異。
![feature7](https://hackmd.io/_uploads/HJdAHP3aR.jpg)
`git rebase`實際上是將feature分支Ｃ、Ｄ版本的異動內容『複製』到原分支(master/main)，並根據版本重新建立對應的提交紀錄(master/main分支的Ｃ、Ｄ版本)。

在GC回收前，仍可以`<commit-hash>`查看feature分支Ｃ、Ｄ版本的內容。
</br>

# 總結
無論是`git merge`或是`git rebase`，都能做到合併分支的效果，主要差異在合併後，分支所呈現的樣子，以及是以何者作為基底執行合併。

執行合併指令前，建議要清楚知道預期的執行結果。

`git merge`與`git rebase`兩者雖然都能做到復原操作，但如果在復原的過程中也操作錯誤，整個復原就會變得更複雜。

另外，若是團隊共同開發，已推送上Remote Repository的，也建議不要再做`git rebase`。
</br>

# 參考資料
https://git-scm.com/book/en/v2/Git-Branching-Rebasing

https://git-scm.com/docs/git-merge

https://june.monster/git-merge-rebase/

</br>

>[!Tip] 
文章內容皆為個人整理的觀點，以及整理後的個人想法，如內容有錯誤或疑慮的部分，歡迎提出討論，收到後會盡快修正！