Subversion 最佳實務
最近因為要改進部門內使用版本控制系統時,所採用的分支、合併策略,因此在網路上找了一些資料。突然看到 Subversion Best Practices - http://svn.collab.net/repos/svn/trunk/doc/user/svn-best-p...,覺得還不錯,便著手將之譯成中文。由於在譯者在翻譯時只著重意譯,並未注重修辭,若有言不達意的地方,歡迎來函指正。
Subversion 最佳實務
這裡提供一組快速的指導原則,讓你能在每天的軟體開發工作中發揮 Subversion 的最大效用。
採用建全的儲存庫配置
儲存庫的目錄配置有許多方式。由於 branches 和 tags 只是一般的目錄,你必須在配置儲存庫的結構時,把它們考慮進去。
Subversion 官方文件建議採用專案根目錄的觀念,來代表專案在儲存庫中的掛載點。專案根目錄裡面僅包含三個子目錄:/trunk, /branches, 及 /tags。一個儲存庫裡面可包含一個或多個專案根目錄。
參考書籍: Choosing a Repository Layout.
以邏輯變更集(changesets)作為提交單位
當你將修改提交到儲存庫時,要確認你的更動反應的是單一的目的:修正一個特定的臭蟲、增加一個新的特性、或是一些特定的工作。你的提交將會產生一個 版本號碼,這號碼在往後可用來作為該次變更的 "名稱"。你可以在臭蟲資料庫中記錄這個號碼,或把它拿來作為 svn merge (合併) 的參數。
參考書藉:"Subversion and Changesets" sidebar, within chapter 4.
善用事例追蹤軟體 (issue-tracker)
盡可能試著建立 Subversion 與 issue-tracker 資料庫之間的雙向連結:
- 盡可能在每個提交的登錄訊息 (log message) 中參引到明確的事例編號
- 在事例中附加訊息時 (描述進度,或是關閉事例),註記相應於此事例變更作業的版本號碼
手動追蹤合併
當提交合併的結果時,切記寫下解釋合併了些什麼的描述性資訊,像是:
將 /branches/foobranch 版號 3490:4120 合併至 /trunk。
參考書藉:Tracking merges manually, and Merging a whole branch to another.
了解混合版本的工作複本
存放工作複本的目錄及檔案可以處於不同的工作版號中:這種特意的設計讓你可以混編不同的新舊版號。但是有些事實是你必須注意的:
- 每次的提交,都會讓你的工作複本包含不同的版號。你剛提交的變更是位於 HEAD 版號中,而其他的部份則屬於之前的版號。
- 有許多的情況不允許提交:
- 若是某檔案或目錄沒有包含在 HEAD 的工作版號中,那你便不能提交其刪除動作。
- 若是某目錄沒有包含在 HEAD 的工作版號中,那你便不能提交其變更屬性的動作。
參考書籍:The limitation of mixed revisions.
處理較大的檔案時要有耐心
Subversion 的優點之一是:在設計上,它並沒有對處理檔案的大小做限制。檔案以 "流(streamily)" 的形式在 Subversion client 及 server 兩端收送,而網路兩端只使用了少許的、定量的記憶體。
當然,有許多實務上的問題需要考量。雖然沒有必要擔心幾 K 位元組大小左右的檔案 (像是一般的原始檔),提交較大的檔案會花費大量的時間及空間 (像是幾十或幾百 mega 位元組大小的檔案)。
首先,記得 Subversion 的工作複本會在 .svn/text-base/ 目錄內儲存了所有接受版本控管檔案的初始複本(pristine copy)。這表示你的工作複本至少會占用原本資料集的兩倍磁碟空間。此外,Subversion client 會採用 (目前無法調整的) 演算法來提交檔案:
- 將檔案複製到 .svn/tmp/ (這會花一些時間,而暫存檔也會占用額外的磁碟空間)
- 對暫存檔與初始複本 (pristine copy) 進行二進位的差異比對,若是新增加的檔案則會拿暫存檔與空檔比對。(這可能會花很長的時間運算,即使最終只有很少量的資料會傳送到網路的另一端)
- 將差異送到伺服器,並將暫存檔移入 .svn/text-base/
因此雖然在理論上沒有檔案大小的限制,你還是得注意,當 client 程式在蹣跚處置較大檔案時,你得要耐著性子等待。然而,你可以放心的是,不像在 CVS,較大的檔案不會讓你的伺服器掛點,或影響到其他使用者。
因應那些不認得 copies/renames 動作的指令
在檔案或目錄複製或更名後,Subversion 儲存庫會追蹤歷程記錄。不幸的,在 Subversion 1.0 裡,善用這項特性的 client 端指令只有 svn log。許多其他指令 (例如 svn diff 及 svn cat) 應該要能自動追蹤更名歷程,但卻還沒這麼做。
面對這種情況,基本的因應之道是使用 'svn log -v' 指令找出舊版的檔案路徑。
例如,假設你在版號 200 中將 /trunk 複製到 /branches/mybranch,並在後續的版號中提交了對 /branches/mybranch/foo.c 的修改。現在你想比較該檔的 80 及 250 版號。
如果你有該分支的工作複本,並執行 svn diff -r80:250 foo.c,你會看到在版號 80 裡面並不存在 /branches/mybranch/foo.c 的錯誤訊息。補救方法是在你的分支或檔案上執行 svn log -v,以得知它在版號 200 之前稱為 /trunk/foo.c,接著就可以直接比較兩個 URL 了:
$ svn diff http://.../trunk/foo.c@80 http://.../branches/mybranch/foo.c@200
確定建立分支的時機
這是經常被爭論的話題,事實上這應該視軟體專案文化而定,而不是一套事先訂定的、放諸四海皆準的政策。我們將討論比較常見的三種型式:
從不分支的系統
(常用於還沒有可執行程式的初始專案)
- 使用者直接將每天的變更提交到 /trunk 中。
- 當某使用者開始提交一連串的複雜變更時,偶爾會造成 /trunk 的破壞 (無法編譯,或不能通過功能測試)。
優點:易於遵字的政策。新進開發人員進入門檻較低。沒有人需要學習如何操作分支及合併。
缺點:開發過程混亂,程式碼可能在任何時間產生不穩固的狀況。
附註:這種開發模式在 Subversion 中比 CVS 裡風險少一點點。因為 Subversion 的提交是單元式的 (atomic),即使當某人正在提交變更時,你也不可能僅取出 (checkout) 或更新 (update) 部分提交的變更。
總是分支的系統
(常用於傾向重度管理及監督的專案)
- 每個使用者在他自己所建立的分支上進行開發工作。
- 當實作完成後,某人 (原來的程式設計師,同儕,或經理) 複審所有私有分支的改變後,再將變更合併至 /trunk。
優點:可以保證 /trunk 在任何時間都相當穩固。
缺點:程式開發工作在此人為因素下與其他人分隔開來,可能產生更多不必要的合併衝突,而需要使用者進行許多額外的合併工作。
當需要時才分支的系統
(這是 Subversion 專案所採用的型式)
- 使用者將每天的工作提交到 trunk 上
- 規則 1:/trunk 必須在任何時間都能編譯,並通過回歸測試,違反此規則的提交者將在眾人面前無地自容。
- 規則 2:單一的提交 (changeset) 不應太大,免得同儕難以複審。
- 規則 3:若是規則 1 與規則 2 衝突 (例如,無法進行一連串的小提交同時保持 trunk 的穩固),那使用者就應建立一個分支,再於該分支上進行一連串的變更集小提交。這可以讓同儕順利進行複審,又保持 /trunk 的穩固性。
優點:可保證 /trunk 在任何時間都很穩固,也不用常常進行煩人的分支及合併。
缺點:會稍微增加使用者每天的工作負擔,他們在每次的提交前必須進行編譯及測試。
留言列表