git merge –ff/–no-ff/–ff-only 三種選項參數的區別解析
前言
git merge
應該是開發者最常用的 git 指令之一,默認情況下你直接使用 git merge
命令,沒有附加任何選項命令的話,那麼應該是交給 git 來判斷使用哪種 merge 模式,實際上 git 默認執行的指令是 git merge -ff
指令(默認值)
對於專業的開發者來說,你可能無須每次合並都指定合並模式(如果需要的話還是要指定的),但是你可能需要知道 git 在背後為你默認做瞭什麼事情,這樣才能保證你的代碼萬無一失。
先說說什麼是 Fast-forward
我們從一個正常開發流程來看看:
開發者小王接到需求任務,從 master 分支中創建功能分支,git 指令如下:
git checkout -b feature556 Switched to a new branch 'feature556'
小王在 feature556 分支上完成的功能開發工作,然後產生1次 commit,
git commit -m 'Create pop up effects' [feature556 6104106] create pop up effects 3 files changed, 75 insertions(+)
我們再更新一下 README 自述文件,讓版本差異更明顯一些
git commit -m `updated md`
這時候我們看看當前分支的 git 歷史記錄,輸入 git log --online -all
可以看到全部分支的歷史線:
f2c9c7f (HEAD -> feature556) updated md 6104106 create pop up effects a1ec682 (origin/main, origin/HEAD, main) import dio c5848ff update this readme 8abff90 update this readme
直接看下圖可能會更好理解一些
功能完成後自然要上線,我們把代碼合並,完成上線動作,代碼如下
git checkout master git merge feautre556 Updating a1ec682..38348cc Fast-forward ....... | 2+++ 1 file changed, 2 insertions(+)
如果你註意上面的文字的話,你會發現 git 幫你自動執行瞭 Fast-forward
操作,那麼什麼是 Fast-forward
?
Fast-forward
是指 Master 合並 Feature 時候發現 Master 當前節點一直和 Feature 的根節點相同,沒有發生改變,那麼 Master 快速移動頭指針到 Feature 的位置,所以 Fast-forward 並不會發生真正的合並,隻是通過移動指針造成合並的假象,這也體現 git 設計的巧妙之處。合並後的分支指針如下:
通常功能分支(feature556) 合並 master 後會被刪除,通過下圖可以看到,通過 Fast-forward
模式產生的合並可以產生幹凈並且線性的歷史記錄:
再說說什麼是 non-Fast-forward
剛說瞭會產生 Fast-forward
的情況,現在再說說什麼情況會產生 non-Fast-forward
,通常,當合並的分支跟 master 不存在共同祖先節點的時候,這時候在 merge 的時候 git 默認無法使用 Fast-forward
模式,
我們先看看下圖的模型:
可以看到 master 分支已經比 feature001 快瞭2個版本,master 已經沒辦法通過移動頭指針來完成 Fast-forward
,所以在 master 合並 feature001 的時候就不得不做出真正的合並,真正的合並會讓 git 多做很多工作,具體合並的動作如下:
- 找出 master 和 feature001 的公共祖先,節點 c1,c6, c3 三個節點的版本 (如果有沖突需要處理)
- 創建新的節點 c7,並且將三個版本的差異合並到 c7,並且創建 commit
- 將 master 和 HEAD 指針移動到 c7
補充:大傢在 git log
看到很多類似:Merge branch 'feature001' into master
的 commit 就是 non-Fast-forward 產生的。
執行完以上動作,最終分支流程圖如下:
如何手動設置合並模式 ?
先簡單介紹一下 git merge
的三個合並參數模式:
- -ff 自動合並模式:當合並的分支為當前分支的後代的,那麼會自動執行
--ff (Fast-forward)
模式,如果不匹配則執行--no-ff(non-Fast-forward)
合並模式 - –no-ff 非 Fast-forward 模式:在任何情況下都會創建新的 commit 進行多方合並(及時被合並的分支為自己的直接後代)
- –ff-onlu Fast-forward 模式:隻會按照
Fast-forward
模式進行合並,如果不符合條件(並非當前分支的直接後代),則會拒絕合並請求並且推出
以下是關於 –ff, –no-ff, –ff-only 三種模式的官方說明(使用 git merge --helo 即可查看
):
Specifies how a merge is handled when the merged-in history is already a descendant of the current history. –ff is the default unless merging an annotated (and possibly signed) tag that is not stored in its natural place in the refs/tags/ hierarchy, in which case –no-ff is assumed.
With –ff, when possible resolve the merge as a fast-forward (only update the branch pointer to match the merged branch; do not create a merge commit). When not possible (when the merged-in history is not a descendant of the current history), create a merge commit.
With –no-ff, create a merge commit in all cases, even when the merge could instead be resolved as a fast-forward.
With –ff-only, resolve the merge as a fast-forward when possible. When not possible, refuse to merge and exit with a non-zero status.
總結:
三種 merge 模式沒有好壞和優劣之分,隻有根據你團隊的需求和實際情況選擇合適的合並模式才是最優解,那麼應該怎麼選擇呢? 我給出以下推薦:
- 如果你是小型團隊,並且追求幹凈線性 git 歷史記錄,那麼我推薦使用
git merge --ff-only
方式保持主線模式開發是一種不錯的選擇 - 如果你團隊不大不小,並且也不追求線性的 git 歷史記錄,要體現相對真實的 merge 記錄,那麼默認的
git --ff
比較合適 - 如果你是大型團隊,並且要嚴格監控每個功能分支的合並情況,那麼使用
--no-ff
禁用Fast-forward
是一個不錯的選擇
到此這篇關於git merge –ff/–no-ff/–ff-only 三種選項參數的區別解析的文章就介紹到這瞭,更多相關git merge –ff/–no-ff/–ff-only內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!