← 上一章:對分支的誤解 下一章:【狀況題】為什麼我的分支都沒有「小耳朵」? →
合併分支
在前面章節的例子中,我從 master 分支開了一個 cat 分支,並且做了兩次 Commit,現在看起來的樣子大概像這樣:

任務執行的差不多了,就要準備合併回來了。如果我想要 master 分支來合併 cat 分支的話,我會先切回 master 分支:
$ git checkout master
Switched to branch 'master'
接下來,要合併分支是使用 git merge 指令:
$ git merge cat
Updating 35c42e..f17acb
Fast-forward
cat1.html | 0
cat2.html | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat1.html
create mode 100644 cat2.html
看一下檔案列表:
$ ls -al
total 16
drwxr-xr-x 9 eddie wheel 306 Aug 18 05:14 .
drwxrwxrwt 84 root wheel 2856 Aug 18 04:29 ..
drwxr-xr-x 16 eddie wheel 544 Aug 18 05:15 .git
-rw-r--r-- 1 eddie wheel 0 Aug 18 05:14 cat1.html
-rw-r--r-- 1 eddie wheel 0 Aug 18 05:14 cat2.html
drwxr-xr-x 3 eddie wheel 102 Aug 17 15:06 config
-rw-r--r-- 1 eddie wheel 0 Aug 18 03:27 hello.html
-rw-r--r-- 1 eddie wheel 161 Aug 18 04:24 index.html
-rw-r--r-- 1 eddie wheel 11 Aug 17 14:56 welcome.html
在 cat 分支新增的 cat1.html 跟 cat2.html,因為 master 現在已經合併 cat 分支,所以現在在 master 分支也有一份了。
回到 SourceTree 看一下目前的狀況:
從左邊的「BRANCHES」選單看得出來現在正處於 master 分支,同時從右方的 Commit 紀錄也看得出來 cat 分支現在領先 master 分支 2 個 Commit:

如果要合併 cat 分支,在分支上按滑鼠右鍵,選擇「Merge cat into master」:

它會跳出一個對話框,點擊 OK 按鈕便可完成合併。這時候再看一下右邊的 Commit 紀錄:

本來落後 2 個 Commit 的 master 分支,在進行合併之後,進度也已經跟上 cat 分支,跟它在同一個 Commit 上。
至於已經合併的分支要不要留下來?請見「【常見問題】合併過的分支要留著嗎?」章節說明。
A 合併 B,跟 B 合併 A 有什麼不同?
這個問題在我一開始學 Git 的時候也曾經困擾過我好一陣子,到底誰合併誰有那麼重要嗎?這就要看你著眼的重點是什麼了。如果以最終結果來看是一樣的,但過程可能會有些差別。我先各別從 master 分支做出了 cat 跟 dog 這兩個分支,並且現在正在 cat 分支:

cat 跟 dog 這兩個分支都是來自 master 分支,可以想像成是「cat 分支跟 dog 分支啊,你們身上都流著我 master 的血…」的意思,所以如果是 master 不管是要合併 cat 或是 dog 分支,Git 會直接使用快轉模式(Fast Forward)進行合併,說得白一點就是 master 直接「收割」 cat 或 dog 的成果了。
但如果是 cat 跟 dog 這兩個分支要互相合併就不一樣了,雖然它們有同樣的來源,但各自長大之後要合併就不會這麼順利了(想想看要你把你的家產跟你哥哥或姐姐的家產合併在一起…)。在這個情況下,Git 會產生一個額外的 Commit 來處理這件事。一般的 Commit 只會指向某一個 Commit,但這個 Commit 會指向二個 Commit,明確的標記是來自哪兩個分支,親兄弟也是要明算帳啊!
來看看會怎麼演變。假設我想用 cat 分支來合併 dog 分支:
$ git merge dog
Merge made by the 'recursive' strategy.
dog1.html | 0
dog2.html | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 dog1.html
create mode 100644 dog2.html
執行這個指令的時候會跳出一個 Vim 編輯器視窗,如果忘記 Vim 怎麼操作,請再回顧一下「超精簡 Vim 操作介紹」章節。為了要進行這次的合併,Git 做出了這個額外的 Commit 物件,這個 Commit 會分別指向 cat 跟 dog 這兩個分支,HEAD 隨著 cat 分支往前,而 dog 分支停留在原地:

如果用 SourceTree 來看會像這樣:

如果改由 dog 分支來合併 cat 分支:
$ git merge cat
Merge made by the 'recursive' strategy.
cat1.html | 0
cat2.html | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cat1.html
create mode 100644 cat2.html
流程上跟剛才幾乎是一樣的。這時候的狀態會變成這樣:

如果用 SourceTree 來看會像這樣:

哪裡不一樣?
你有看出哪裡不一樣嗎?其實就以結果來看,不管是誰合併誰,這兩個分支的檔案最後都拿到了。你可能看 SourceTree 的畫面,會認為誰合併誰會有誰在前面、誰在後面的差別,但事實上並不是這樣,那只是因為軟體沒辦法畫出來「平行」的效果而已。
事實上不管誰合併誰,這兩個分支上的 Commit 都是對等的。硬是要說哪裡不一樣,就是 cat 分支合併 dog 分支的時候,cat 分支會往前移動,反之亦然。不過前面曾經提到分支就像貼紙一樣,隨時要刪掉或改名都不會影響現在已經存在的 Commit。
有啦,真的不一樣的還有一點,就是這個為了合併而產生的這個額外的 Commit 物件,裡面會記錄兩個老爸是誰,誰合併誰就會有「誰放前面」的差別,不過這可能就有點太過細節了。
這是 cat 分支合併 dog 分支,所以 cat 分支 b174a5a95a 放前面:

這是 dog 分支合併 cat 分支,所以 dog 分支 053fb212bb 放前面:

這很重要嗎?國外曾經有一個 Ruby 跟 Python 一起合辦的研討會名字叫做 RuPy (後來已改名成 PolyConf),那為什麼 Ruby 要放前面?Python 的人可能會想為什麼不叫 PyRu?這大概就跟 A 合併 B 跟 A 合併 B 的差別差不多吧。
Comments