最近更新: 2008-05-07

請在「持續整合」的原則下利用版本控制工具的合併功能

前一陣子在工作場所碰到一件事,我的同事抱怨 SVN 不能幫他合併他修改過的分支內容。我覺得很奇怪,因為我並沒有碰過這種情形。一開始我以為他是不熟悉 TortoiseSVN 工具,後來我實際看了他操作後,看到他竟然一次要合併近百份源碼檔,當場無言以對。

我記得我曾說過 SVN 可以幫我們程序員自動合併分支的源碼內容,並在衝突時提示我們。然而,在碰到同事這件例子後,我發覺我忘了加一個但書: 「請在持續整合(Continuous Integration)的原則下利用合併功能」。否則再好的版本控制工具也無法幫你合併。

程式員每天簽入他們的程式碼,而且整合好幾次。

當程式員完成修改後將它簽入時,心裡必須有所準備得要合併別人在之前先行簽入所作的改變。為了避免合併花費太長的時間,團隊的成員會頻繁地把模組簽入。

Robert Martin, 《敏捷軟體開發原則、樣式與實務》, 章節2.1.8: 持續整合

先說說我個人的使用習慣。首先,當我寫了一份源碼及測試案例後,即便只寫好類別的外觀宣告,我仍會提交(commit)。接著,我會按照類程內容的實作進度與重整範圍有規律地 提交源碼。而在上午午餐與下午下班前30分鐘左右,就會進行一次整合,並執行整合性測試案例組合 (test case suite)。當我需要利用 SVN 的「合併(merge)」功能時,基本上就是在整合之時。以我這種提交頻率,一次合併的源碼文件屈指可數(也就是小於10份源碼文件),而且一天至少兩次。

在這種頻率下,SVN 的合併功能確實有效地幫我完成了幾乎全部的源碼合併動作。即使有衝突,一般也就兩、三處,按按滑鼠選擇要採用的段落就解決了。

我那同事的情形則相反。就我所知,他甚至隔了三、四天才做合併,而且已經修改了近百份源碼檔。於是,當他執行合併功能時,光跳出來的衝突提示就令人眼花繚亂了。還有一點,人是善忘的,經過兩、三天的時間後,他已經想不出來改過哪些地方以及為何而改。他必須逐一地反覆查看衝突段落的前後文,拿起電話聯絡其他修改者,才能決定那些段落要採用,而哪些段落要重寫。沒錯,就是重寫,這意味著有些地方的修改工作前功盡棄。

啊,差點忘了最重要的一件事。那就是他沒有寫測試案例的習慣(事實上,公司除我以外,大概都沒有這習慣,他們認為那是測試部門的工作)。而在這麼大規模的異動後,不難想像合併後的源碼是錯誤重重。於是重新測試與除錯,又是一件巨大的苦差事。

我記得那位同事後來大概又花了兩天的時間才把他那些源碼內容合併起來。現在,他每天下班前都一定會合併一次 (不過他還是沒有寫測試案例)。他抱怨 SVN 不能合併的次數終於變少了。

樂多舊網址: http://blog.roodo.com/rocksaying/archives/5990201.html

樂多舊回應
ypochien@gmail.com(生魚片) (#comment-16378573)
Fri, 09 May 2008 00:15:17 +0800
石頭成大哥您好:

如果工作的原始碼都會經過加密,而且其包含介面(UI Control) 與 Code. .

有甚麼樣的版本控管比較適合或是可以嘗試的.

我現在只能用SVN來幫我做其個別檔案的版本控制. 但是無法使用其他的功能,例如您所提的合併.或者差異比較之類的.

另外針對測試先行的部分,是否得取決於個人的程式編寫風格? 總覺得我連 模組或類別 的判斷都不足,是否也就無法以測試案例來做為開發的方法?
my@esast.com(MaoYang) (#comment-16405303)
Mon, 12 May 2008 18:08:50 +0800
很不錯的經驗分享, 我的習慣是每完成一個task or 功能模組,就會做一次commit, 而且這個commit會伴隨一個task id or bug id,再利用svn hook功能將change set與task or bug db association,這樣就很容易追蹤我每次的修改是為那一個task or bug做commit.
未留名 (#comment-16409713)
Tue, 13 May 2008 10:59:46 +0800
to 生魚片:

為什麼你的工作源碼要加密?
只有 release/export 給客戶的內容才需要加密。

測試先行跟個人程式編寫風格無關。

程式編寫風格是個人的 coding standard,它主要表現在你的變數命名、括號對齊等方式。跟你的開發流程無關。

如何畫分單元模組?這要看經驗。但是有2種編程觀念可以幫助你快速養成這種經驗,一是 MVC ,另一是 TDD(測試先行)。

當你無法輕鬆地先為一個預想中的單元編寫出測寫案例時,就是一個警標。它正提醒你:你所預想的單元不是一個好的設計。(太高的耦合度、太多的工作目標,等等)

所以,並不是你的經驗不足就無法導入測試先行的開發方式。事實相反,正是因為經驗不足,更要導入測試先行的開發方式,才能及早發現不良的設計,並快速養成正確的設計經驗。

*****************

to MaoYang:

習慣上,我用 revision 編號作為你說的 task id。至於是否要透過 hook 自動儲存提交時的 異動訊息,則視情況而定。

因為我提交的內容中,有不少是重構的結果,反而只有少數工作是針對使用者提報錯誤的debug。基於使用頻率,我是自行到 bug trace system 輸入相對應的 revision 編號。

不過我只輸入 revision 編號,意味著其他人需要再去搜尋 svn 的 log 才能看到異動訊息。

你的作法倒是提醒我了。我想想,也許我是該寫個 hook,一併把異動訊息上傳給 bug trace system。

不過我應該會在異動訊息中加上一個 tag ,用來標明這次異動是針對哪個 bug ticket id,並提示hook上傳給 bug trace system (沒有那個 tag 就不上傳)。