﻿# 講解 Subversion 分支與合併：以 TortoiseSVN 為例

在實務的版本控管情境中，套用分支與合併應該是最方便不過的了，會用的人可以得到許多版本控管的好處，但不會用的人卻會因為不理解而害怕使用它，由於 Subversion 1.5 開始新增了 [Merge Tracking](https://subversion.apache.org/docs/release-notes/1.5.html#merge-tracking) 功能，可有效降低維護分支的負擔，所以能學會**分支與合併**的技巧對整個版本管理流程來說會有非常大的幫助，今天我就來講解幾個利用 [TortoiseSVN](http://tortoisesvn.net/) 實際的操作分支與合併的例子。

如下圖是一個很常見的分支示意圖，當你想在 trunk 發展一個新功能時，你可以透過 svn copy 的方式將整個 /calc/trunk [廉價複製](http://svnbook.miniasp.com/1.4/svn.branchmerge.using.html)到 /calc/branches/my-calc-branch，當 /calc/branches/my-calc-branch 分支完成所有新功能開發後，再將所有變更一次合併回 /calc/trunk 開發主線。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/8c0aac04524d87de7b3c-image.png)

我講的 svn copy 其實就是對應到 TortoiseSVN 的 Branch/tag 功能

 ![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/e18a621341e20065abb8-image.png)

使用時應注意以下：

1.  你要廉價複製的來源路徑
2.  你要廉價複製的目的路徑 (「複製」就等同於「分支」，這是 SVN 附加上去的意義 )
3.  寫下你為什麼要建立這個分支、用途是什麼，這訊息可以給團隊成員或版本經理看
4.  我們可以在執行 Copy (Branch/tag) 的同時**順便**將你的「工作目錄」切換至「分支的路徑」

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0ec52a99fe98c2bf42e4-image.png)

這時我們可以看一下 trunk 這個目錄的屬性，並切換至 Subversion 頁籤，你會發現該「工作目錄」所對應到的 Subversion 路徑已經變更到 /calc/branches/my-calc-branch 了。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0228de27fbd1a9028212-image.png)

但為了怕初學者混淆，我還是先將 /calc/trunk 切換回原本的 SVN 路徑：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/5496a0fd9e7a90808fc6-image.png)

這裡有幾點注意：

1.  這裡是你的「工作目錄」(Working Copy)
2.  這裡才是你要將「工作目錄」切換到的 SVN 路徑，也就是將 /calc/branches/my-calc-branch 切換至 /calc/trunk 路徑

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0fef3389470c3a944d04-image.png)

這時你便可以開始在 /calc/branches/my-calc-branch 發展你這次想要新增的功能，且不會影響到其他團隊成員正在發展或維護的 /calc/trunk 開發主線。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/b18b85c4411d8dd3a21c-image.png)

也許過了一段時間，原本的 /calc/trunk 開發主線可能已經有其他團隊成員陸續修正了一些 Bugs，但這時你的分支 /calc/branches/my-calc-branch 就可以直接套用 **開發主線** ( /calc/trunk ) 的更新，除了避免重複的工作外 (重複除錯)，也可以避免版本的衝突發生，因為兩個人改同一個已知的 Bug 可能會因為用不同方法除錯或命名的方式不一致而發生衝突。

經常將 **開發主線** ( /calc/trunk ) 的變更透過 svn merge 合併至 **分支線路** ( /calc/branches/my-calc-branch ) 是一個非常好的習慣，這樣才不會讓你因為脫離 **開發主線**(**trunk**) 過久而導致將 **分支線路** ( /calc/branches/my-calc-branch ) 合併回 **開發主線** ( /calc/trunk ) 時發生許多版本衝突。

 ![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/07c77c1073927d1b4142-image.png)

從 **開發主線** ( /calc/trunk ) 合併至 **分支線路** ( /calc/branches/my-calc-branch ) 通常選第 1 個，也就是 \[**Merge a range of revisions**\]

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/aae50ac2718fc1378fa9-image.png)

在 Merge 的視窗有以下注意事項：

1.  設定要合併的來源，由於我們打算從 **開發主線** ( /calc/trunk ) 合併分支這段時間所產生的變更至 **分支線路** ( /calc/branches/my-calc-branch )，所以合併的來源要選擇 /calc/trunk 才對！
2.  合併的結果會直接與目前「工作目錄」(Working Copy) 做比對，並修改目前工作目錄中的所有檔案。因此建議在做合併之前可以將所有尚未 commit 的檔案先 commit 到版本庫，避免不必要的衝突事件發生。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/512dde13cb99c08935be-image.png)

在正式進行合併(Merge)之前，建議先執行 **Test merge** 看看是否會發生什麼事!

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/97e88f066a38e82469a6-image.png)

若無異狀則可直接按下 \[Merge\] 按鈕進行合併動作，這時從 **開發主線** ( /calc/trunk ) 分支出來的到目前工作目錄的版本就會做個比較，然後直接套用變更到你現有的檔案、目錄或屬性裡。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3b279da1a94ddad5e26f-image.png)

在合併之後如果沒有發生衝突，不代表真的沒衝突，所以必須再次對原始碼做出驗證後才能 commit 進版本庫，建議可參考以下流程：

1.  將專案進行建置(Build)
2.  如果沒問題再對專案進行單元測試(Unit Testing)或手動測試(Manual Testing)
3.  如果都沒問題再 commit 目前合併無誤的版本到版本庫！

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/9b8c8f8a87a6f65d3e54-image.png)

最後我們的 my-calc-branch 分支已經將新功能開發完成且測試無誤，所以要將 **分支線路** ( /calc/branches/my-calc-branch ) 的最終版本合併回 **開發主線** ( /calc/trunk )，這時的手續如下：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/a3bbbd5685687c500811-image.png)

從 **分支線路** ( /calc/branches/my-calc-branch ) 合併回 **開發主線** ( /calc/trunk ) 通常選第 2 個，而特別選擇 \[**Reintegrate a branch**\] 這個選項是很重要的，因為這有以下好處：

1.  讓 Subversion 能知道 **開發主線** ( /calc/trunk ) 是從哪個分支、哪些版本合併進來的
2.  有效節省 Subversion Repository (SVN儲存庫) 的空間，因為不用重複儲存分支的所有變更資訊
3.  可以產生 Revision graph 得知專案開發的分支狀況

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/113961865b3084dde3ee-image.png)

一樣可以先 **測試合併**(Test merge) 再正式進行 **合併**(Merge)

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/fdf90285a84e90f78d5b-image.png)

合併完後再將變更 commit 到版本庫

 ![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/19f0f2b71e62d98d321f-image.png)

 ![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/67b97e0d1f6f59ac9772-image.png)

當 **分支線路** ( /calc/branches/my-calc-branch ) 合併回 **開發主線** ( /calc/trunk ) 並 commit 了之後，該分支就沒用了，該分支如果未來不再更新或繼續開發~~，Subversion 也不會繼續追蹤這個分支的變更 (因為之前已經 Reintegrate 過了)~~，建議將該分支刪除。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/12e8c96f8b1e0f6f97db-image.png)

刪除後要記得 commit 才能將「刪除動作」寫入到 Subversion Repository (SVN儲存庫) 中

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/40bf968ef5612a7479a5-image.png) 

[![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/42560f2a1911c9168764-image_thumb.png)](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0e1109bd637e038305cf-image.png)

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/2f0af1e93e4b91e00cff-image.png)

以上就是一個 Subversion 分支與合併的完整過程，但有許多很細部的觀念我很難在一篇文章裡講清楚，如有時間建議多閱讀 [Subversion 線上文件](http://svnbook.red-bean.com/en/1.5/)，當你建立起更多更完整的觀念後，對 Subversion 甚至是其他版本管理工具應該都能夠更加得心應手！

**相關連結**

-   [Version Control with Subversion For Subversion 1.5](http://svnbook.red-bean.com/en/1.5/)

-   [Chapter 4. Branching and Merging](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.html)

-   [Basic Merging](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.basicmerging.html)

-   [Subversion 1.5 Release Notes](https://subversion.apache.org/docs/release-notes/1.5.html)
-   [Understanding the internals of Subversion's merge tracking feature](http://www.collab.net/community/subversion/articles/merge-info.html)
