← 上一章:對分支的誤解 下一章:【狀況題】為什麼我的分支都沒有「小耳朵」? →
合併分支
在前面章節的例子中,我從 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