LoginSignup
2

More than 5 years have passed since last update.

Git 的 Merge 與 Fast-Forward

Last updated at Posted at 2015-12-18

(日本語はまだ、中国語ですみません :sweat_drops:

台湾人の 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 ,長得如下圖

image

說明:
- 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 裡面看就會長這個樣子:

image

進行 Merge

預設的 merge

這時候執行

git merge b-01

這時候就會看到終端機有跳出回饋的訊息:

Updating 464aead..0169033
Fast-forward

提示我們他只是幫我們把目前 HEAD 所指到的 master 的指標位置換到 0169033

在 SourceTree 裡面看,就變成這樣了:

image

我的 branch 怎麼不見了(慌張)

因為 fast-forward 的關係,b-01 分支的特徵也就變得無法辨識了

Merge 時不要 fast-forward

在 merge 指令有個 —-no-ff flag,可以告訴 git 這次的 merge 無論如何都不要進行 fast-forward 。

開始前,可以在另外一個資料夾,在進行一次前置作業所做的事情,確認一下你的 git repo 是不是目前這個狀態:

image

執行指令

在 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 的分支特徵也保留下來:

image

除此之外,加上 --no-ff 之後就有加一次 merge 的 commit 記錄這一次的變更

加上 --no-ff 的優缺點

優點

在開發一個功能時,通常都會開一支新的分支,使用 --no-ff 可以讓成員在日後可以很清楚辨識不同的功能所包含的 commit 歷程有哪些

除此之外,GitHub merge pull request 的策略,也是使用 --no-ff ,也是讓開發者可以方便辨別。

缺點

假使這個 task 或是 bug-fix 只有一個 commit ,很容易造成一堆小耳朵的存在,如下圖:

image

對策

  • 思考 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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2