(日本語はまだ、中国語ですみません )
台湾人の vc7 です。
在一般使用 Git 的開發日常中, branch 的新增和 merge 是很常見的事情。進行 merge 的時候,git 預設會以 fast-forward 的模式進行。
那什麼是 fast-forward merge 呢?和 no fast-forward 的 merge 有什麼差別?
Fast-Forward Merge 是什麼
當你目前的位置 (HEAD
) 是某個要被 merge branch 上的 commit 的 root commit ,在沒有任何新的 commit 的情形下,要 merge 回來的時候,就會觸發 fast-forward 。
由於在原本的分支上沒有新的變更紀錄需要被 merged ,預設就會觸發 fast-forward merge ,就會直接把這個 commit HEAD
移動到要被 merge 的 commit 的位置,也不會新增一個 merge commit 。
前置作業
首先我們要先準備一系列含有 branch 的 commit ,長得如下圖
說明:
- HEAD - 當前所在位置,指標位置指向 master
- 藍色標籤 - branch 指標所指的 commit 位置
- 灰色底的文字 - commit messages
建立資料夾並初始化 git repo
打開終端機之後,移動到你想要的資料夾
mkdir git-ff-demo
cd git-ff-demo
git init
做幾個 commit 、建立 branch 後,再回到 master 上
初始化 git repository 之後,預設就會在 master 上。為了降低複雜度,這個範例在 commit 時會用到另外一個 flag - —-allow-empty
,可以讓你不用變更資料夾的情形下就可以執行 commit 。
git commit —-allow-empty -m “Initial Commit”
git commit —-allow-empty -m “a”
建立兩個 commit 之後,現在來建立如圖中的 b-01
分支
git checkout -b b-01
接著在 b-01
上再繼續多 commit 兩個變更
git commit —-allow-empty -m “b”
git commit —-allow-empty -m “c”
最後 checkout 回到 master
,準備把 b-01
merge 到 master
上:
git checkout master
這樣子就完成事前準備了,如果在 SourceTree 裡面看就會長這個樣子:
進行 Merge
預設的 merge
這時候執行
git merge b-01
這時候就會看到終端機有跳出回饋的訊息:
Updating 464aead..0169033
Fast-forward
提示我們他只是幫我們把目前 HEAD
所指到的 master
的指標位置換到 0169033
在 SourceTree 裡面看,就變成這樣了:
我的 branch 怎麼不見了(慌張)
因為 fast-forward 的關係,b-01
分支的特徵也就變得無法辨識了
Merge 時不要 fast-forward
在 merge 指令有個 —-no-ff
flag,可以告訴 git 這次的 merge 無論如何都不要進行 fast-forward 。
開始前,可以在另外一個資料夾,在進行一次前置作業所做的事情,確認一下你的 git repo 是不是目前這個狀態:
執行指令
在 merge 的指令中,加上 —-no-ff
即可:
git merge —-no-ff b-01
(接著可能會跳出 vim 的編輯畫面,輸入 :wq
儲存並關閉就可以完成 merge commit)
這時候終端機就會跳出以下訊息,
Already up-to-date!
Merge made by the 'recursive' strategy.
來到 SourceTree 看,也就可以看到 b-01
branch 的分支特徵也保留下來:
除此之外,加上 --no-ff 之後就有加一次 merge 的 commit 記錄這一次的變更
加上 --no-ff
的優缺點
優點
在開發一個功能時,通常都會開一支新的分支,使用 --no-ff
可以讓成員在日後可以很清楚辨識不同的功能所包含的 commit 歷程有哪些
除此之外,GitHub merge pull request 的策略,也是使用 --no-ff
,也是讓開發者可以方便辨別。
缺點
假使這個 task 或是 bug-fix 只有一個 commit ,很容易造成一堆小耳朵的存在,如下圖:
對策
- 思考 task 規劃時的範圍是不是切太細?
- 或是在 git 流程中,啟用 hot-fix 之類的 branch 來負責 bug fix 的 commits ,零碎的 hot-fix 可以直接在這個 branch 上解決,比較龐大的 bug fix 再另外建立 branch 來負責
結語
我第一次執行 merge 的時候就有發現我的 branch 被 fast-forward merge 掉了,第一次看到真的有嚇到;到後來才知道原來這個叫做 fast-forward 。
幫團隊做 code review 後需要 merge 的時候,也都是使用這個方式保留 branch 的特徵(當時公司內還沒有採用 PR 的機制,所以都是手動來的)。
這篇的優缺點是我自己的想法和心得,如果有任何的想法和討論都可以在下面留言唷!
如果覺得這篇不錯,可以分享、或是點最最最上面的 Stock 按鈕儲存起來,謝謝您。
參考資料
本篇環境: Mac OS X 10.11, git 2.6.2, SourceTree 2.0.5.2