前一陣子,在 twitter 上看到 GitHub 在三月份要來臺灣做教育推廣,剛好中研院資訊所有老師在 03/23 也有邀請 GitHub 來演講。
03/23 當天是 GitHub 員工 John Britton 擔任講者,主要是介紹 Git 、GitHub 使用,自己雖然開發會用 Git 來管理程式碼,但是只對操作上比較熟悉,在整個演講中,又重新了解一些 Git 運作方式,收穫蠻多的,剛好也有人問到一個 Fast-forward 的問題,當下並沒有很清楚了解,因為,演講完之後,有 GitHub 貼紙可以拿,拿到貼紙之後,回到辦公室其實已經忘記了 XD,還好同事有問我知不知道 Fast-forward,立馬在辦公室就找了一下資料。
什麼是 Fast-forward?
簡單來說,Fast-forward 是 git merge 的一種方式,git merge 主要是將不同 branch 中的內容合併到某一個 branch 內。為什麼會特別區分這種方式呢?
用一張圖來解釋:
Git merge 前
- 有一個
master
branch,在master
branch 中,已經有了 3 個 commits 了 m3
commit 後,建立了一個develop
branchdevelop
branch 建立 2 個 commits
目前到這裡,是 git merge
前的操作,而 2 個 branches,分別有 2 個 pointer 指著 branches 的最新 commit 節點。
之後先切換到 master
,將 develop
branch 合併 (merge) 到 master
branch:
$ git checkout master $ git merge develop Updating 5a51d31..129acb8 Fast-forward d1 | 0 d2 | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 d1 create mode 100644 d2
把 develop
合併到 master
後會發現,其實 git 只是將原本指向 m3
commit 節點的指標,移到 d2 ,怎麼會這樣呢?
蠻容易可以了解的,因為 develop
branch 建立之後,在 master
branch 中並沒有再進行修改(也就是建立新的 commit),所以要把 develop
合併到 master
的話,就是 develop
最新的 commit 的內容了!
反之,develop
branch 建立之後,如果 master branch 還有再被修改,之後的合併,就沒辦法使用 fast-forward 來進行合併。
從以下圖可以了解:
- 一開始一樣與 Git merge 前所敘述的一樣
- 在
develop
branch 建立後,在master
branch 中又進行了修改、建立 commits,所以指向master
branch 的指標,已經移到m5
commit - 接著,要將
develop
branch 的內容合併到master
branch 中,此時,會發現無法使用 fast-forward 將指向master
的指標指向develop
branch 的最新 commit 節點,因為,master
branch 已經在建立develop
branch 之後被修改了,所以需要將develop
的內容與master
合併之後,建立一個新的m6
commit
不使用 Fast-forward
也可以在 git merge 的時候,不使用 fast-forward 的方式來進行合併:
- 不使用 fast-forward 的話,把 2 個 branches 內容合併之後,會建立一個新的 m4 commit 節點
如何不使用 fast-forward?
只要在 git merge
指令之後加上 --no-ff
即可:
$ git checkout master $ git merge --no-ff develop Merge made by the 'recursive' strategy. d1 | 0 d2 | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 d1 create mode 100644 d2
為什麼不直接使用 fast-forward 要使用這種方式呢?
先來瞭解一下,有沒有 fast-forward,git log 看起來差別在哪:
有 fast-forward (develop 合併到 master 後):
commit 932154590bde6dd8c7329439870ae893e8b6bdf4 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:58:34 2015 +0800 d2 commit 129acb8246636279a28352f91a5c1a724a2d7a6d Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:57:11 2015 +0800 d1 commit adf8e08abdfe5d93acb24d9e0d43b89b4aa8d211 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:45:17 2015 +0800 m3 commit 5a51d311899f0b8520d16b276291e80735bf90b8 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:43:19 2015 +0800 m2 commit 09fd8ae6de5c0f718af12847d7c97364eb738fd2 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:42:49 2015 +0800 m1
沒 fast-forward (develop 合併到 master 後):
commit bc943817e068304f9de6285bd8c9f1a9a108e952 Merge: adf8e08 9321545 Author: YMHuang <MY_EMAIL@email.com> Date: Sun Apr 5 12:56:40 2015 +0800 Merge branch 'develop' commit 932154590bde6dd8c7329439870ae893e8b6bdf4 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:58:34 2015 +0800 d2 commit 129acb8246636279a28352f91a5c1a724a2d7a6d Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:57:11 2015 +0800 d1 commit adf8e08abdfe5d93acb24d9e0d43b89b4aa8d211 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:45:17 2015 +0800 m3 commit 5a51d311899f0b8520d16b276291e80735bf90b8 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:43:19 2015 +0800 m2 commit 09fd8ae6de5c0f718af12847d7c97364eb738fd2 Author: YMHuang <MY_EMAIL@email.com> Date: Sat Apr 4 14:42:49 2015 +0800 m1
從上面的例子可以看到,如果沒有使用 fast-forward,能知道到哪些 commits 是從其他 branch 合併進來的,而且能在合併的時候加上 commit 訊息。
如果使用 fast-forward 合併,刪除被合併的 branch 後,原本的 commit 會不見嗎?
當然不會,以上面的例子來說,如果 develop
branch 合併到 master
branch 後,要將 develop
branch 刪除,只是會把指向 develop 的指標移除,所以不會讓 develop
branch 中的 commits 節點也被移除掉。
發佈留言