iT邦幫忙

2

Git-fast-forward快轉模式

git
WM 2019-05-12 20:07:261385 瀏覽

前一篇介紹的Git-如何解決合併衝突,說明了在合併過程中可能遇到的衝突。
成功合併之後也有可能遇到另一個情況,「fast-forward(快轉模式)」

何謂快轉模式

這是上一篇成功合併的線圖。
https://ithelp.ithome.com.tw/upload/images/20190519/20112573RrS34ZgA8e.png

把feature分支刪除,並且在master分支上,再重建一個feature分支。
https://ithelp.ithome.com.tw/upload/images/20190511/20112573Yu7zmUWJR0.png

此時,feature分支與master分支,都是同一個版本。
https://ithelp.ithome.com.tw/upload/images/20190511/20112573n2nFpuAKxV.png

在feature分支:
執行cat,查看a.txt的內容。
將內容改成123。
執行git diff查看修改前後的差異。
https://ithelp.ithome.com.tw/upload/images/20190511/20112573XFHRegQM1m.png

commit新版本
https://ithelp.ithome.com.tw/upload/images/20190511/201125734ihqgf09RS.png

feature分支比master分支領先一個版本。
https://ithelp.ithome.com.tw/upload/images/20190511/20112573jc5vGgfKrn.png

為了讓fast-forward(快轉模式)更明顯,再新增2個檔案。

這樣一來,feature分支會比master分支領先3個版本。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573iznsm7EBKW.png

在master分支合併feature分支。
https://ithelp.ithome.com.tw/upload/images/20190512/201125730mqKQOrEOX.png
這時會發現,一個訊息:Fast-forward
表示這次的合併,採用了fast-forward(快轉模式)。
那fast-forward(快轉模式)究竟是什麼情況?

查看log
https://ithelp.ithome.com.tw/upload/images/20190512/20112573aEZYOZPIvz.png
目前,master分支跟feature分支位於同一個版本,這是可以預期的情況,畢竟是master分支合併feature分支。

來看看線圖。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573JROtkM13Jz.png
重點來了,跟上一張線圖比較後,會發現master分支從(Merge branch 'feature')版本直接跳到跟feature分支同一個版本(add c.txt)。
線圖並無分岔,而是一條線直接跳上去(黑色)。
這種線圖沒有分岔,而直接跳到最新版的情況,就是fast-forward(快轉模式)

分析fast-forward

一開始,feature分支與master分支,是同一個版本。
意味著,它們擁有相同的檔案與內容。
https://ithelp.ithome.com.tw/upload/images/20190511/20112573n2nFpuAKxV.png

然後,feature分支commit了3個新版本。
也就是領先master分支3個版本。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573iznsm7EBKW.png

當master分支要合併feature分支時。
它們之間的差異,就只是feature分支比master分支多3個commit而已,其他都是一模一樣。
換句話說,master分支有的feature分支都有。
畢竟它們都是從同一個commit分出去的。

master分支合併feature分支,就等同於合併自己以後的版本。
此時,git就會啟用fast-forward,master分支一口氣跳了3個版本,
到feature分支最新的commit(add c.txt)。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573JROtkM13Jz.png

關閉fast-forward

表面上看來,fast-forward合併,並沒有任何問題,結果也都成功合併。
但請仔細思考,分支的意義是什麼?

在軟體開發過程中,會有一條主要分支,其他分支,不管它的任務是什麼,最後,都會併入主要分支。
master分支是主要分支,而feature分支是開發中的分支,master分支直接跳到feature分支的最新commit,是有點奇怪。
這邊要強調,以git的觀點,fast-forward沒有不好,我們是以軟體開發的觀點來討論這個問題。

解決方式就是將fast-forward合併關閉,讓master分支與feature分支的合併,看起來就像是開發中的分支(feature)併入主要分支(master)。

執行git reset --hard ORIG_HEAD,回復合併之前的版本。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573jQnLxgweF6.png

master分支回到原本的版本。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573QJAZ7Ak4tJ.png

再次合併,這次關閉fast-forward。
指令 --no-ff,關閉fast-forward。
執行git merge feature --no-ff。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573PBepUDJe2n.png
這次合併訊息,沒有Fast-forward字樣。

確實執行分支合併的動作。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573hqoh60RCoC.png
由線圖可以看出,master分支的確合併feature分支,並做了一次commit(Merge branch 'feature')。
合併之後,feature分支可以再繼續開發,再繼續併入master分支。

feature分支再新增檔案。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573aAbyCckA08.png

再次併入master分支。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573AJwETCLlzd.png

這樣的線圖非常一目瞭然。

fast-forward的缺點

一般來說,我們不會在主要分支,執行開發、修復、測試這些操作,一定都是確認穩定後,再併入主要分支。
從線圖上可以看出哪些分支做了哪些commit,再合併入主要分支。

master分支的黑正方,表示合併後的commit,黑圓點,表示自身的commit,
紅圓點表示feature分支的commit,這樣不是很清楚嗎。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573HiG4q6ZB8H.png

但如果透過fast-forward合併的話,並不會產生合併的commit,且全部的commit都擠在同一條線上,包括master分支,如此一來,我們就很難判斷分支commit的情況。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573JROtkM13Jz.png

那到底fast-forward適合用在什麼情況呢?

適合fast-forward的情況

我們先在GitHub,新建一個repository,並上傳本地專案。
詳細步驟可以參考Git-上傳檔案至遠端儲存庫

上傳成功後可以發現,多了一個origin/master分支,代表遠端儲存庫的master分支,
目前跟本地端的master分支指向同一個版本。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573uhomPYPa8K.png

查看前5筆的log
https://ithelp.ithome.com.tw/upload/images/20190519/20112573fKJb1jQzyh.png

master分支(本地)與origin/master分支(遠端),雖然是不同分支,但它們意義上是相同的,都是master。
所以它們應該要同步才對。

我們來模擬一個多人分工,大家都在origin/master分支開發的情境。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573M4VZmBBVDG.png

將專案clone下來,跟原本的範例不同位置。
模擬同事A的開發。
詳細步驟可參考Git-git clone 的各種方式
https://ithelp.ithome.com.tw/upload/images/20190519/2011257390mANCS3Y3.png

假設同事A修改b.txt後,push至遠端儲存庫。
https://ithelp.ithome.com.tw/upload/images/20190519/20112573JVRhpFJAAB.png

這時,遠端的origin/master分支有16個commit。
https://ithelp.ithome.com.tw/upload/images/20190519/20112573tYjuRGUMW6.png

而本地端的master分支有15個commit。
https://ithelp.ithome.com.tw/upload/images/20190519/20112573DucoNa5pGx.png
所以遠端的origin/master分支領先本地端的master分支一個版本。

必須得將遠端的origin/master分支下載回來,才能更新版本狀態。

執行git pull,可以下載更新。
但實際上git pull是由兩個命令所組成的:git pull = git fetch + git merge。
也就是說,它會執行兩個動作。
將變更的部分先下載回來(git fetch),再執行合併(git merge)。

執行git fetch
https://ithelp.ithome.com.tw/upload/images/20190512/20112573wVeRrN0lq1.png

查看線圖。
https://ithelp.ithome.com.tw/upload/images/20190519/20112573VptbOdMmvf.png
origin/master分支領先master分支一個版本,這是由同事A所push上去的。

既然已經有新版本了,那就得將master分支合併origin/master分支,我們跟同事A的專案才能同步。

重點注意,這時要採用哪種合併呢?
剛剛我們將fast-forward關閉,是因為master分支與feature分支,意義上是屬於不同的分支,才需要讓線圖分岔。
但目前的情況是,master分支與origin/master分支,意義上都是相同的分支,既然如此,那直接讓master分支一直線上去,是比較合乎邏輯的。線圖分岔,反而會覺得奇怪。

採用fast-forward合併。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573gxkc3wvNRe.png

讓master分支直接跳到origin/master分支的版本。
https://ithelp.ithome.com.tw/upload/images/20190512/20112573rZqvmH1Z1b.png

結論

使用fast-forward的情況:合併的分支,代表相同的意義。
關閉fast-forward的情況:合併的分支,代表不同的意義。

本文為觀看網路教學的學習筆記。


尚未有邦友留言

立即登入留言