從前從前,有一個軟體產品,叫它 XYZ 吧!XYZ 一炮而紅,廣受歡迎,為了爭取更大的銷售,XYZ 的產品經理小強決定跨出 Windows 的世界,做個 XYZ for Solaris,Project Lead 小明就從 XYZ for Windows 拉一個 branch,把 XYZ 給 PO 到 Solaris 去;後來,小強發覺 Solaris 不紅,決定再做個 XYZ for Linux,小明就又從 XYZ for Solaris 上拉一個 branch,要 PO 到 Linux。
這時候,這棵 source code 的樹長這個樣子:
XYZ for Windows
└ XYZ for Solaris
└ XYZ for Linux
故事還沒完,精彩的才要開始。
Linux 才在做,已經在賣的 XYZ for Windows 與 XYZ for Solaris,免不了有客戶反應有 bug 要修、有新功能要加,要出好幾個語言版本,更必須要出個 version 1.1 好照顧既有的顧客;同時,評價不錯的 XYZ for Windows,小強也提出 Version 2.0、3.0 的 product roadmap,預計來年上市。甚至,小強還想找個 Hardware Vendor 來「策略聯盟」,推出 XYZ Appliance。小強心想:反正,每個產品的 code 都差不多,改一改又是一個新產品咩!新產品愈多,產品線愈大,賺錢愈多的啦!
既然有錢賺,當然也不會吝於找更多人來做 project,於是乎,小明做 Linux、小華做 version 2.0、小美出 hot fix、小麗做 Appliance、還有大雄去做八國語言版,各個 project 分頭進行,大家做得不亦樂乎!這時候,XYZ 產品線的 development branch,悄悄地長成這樣了...

(Credit: eleda 1)
時間飛逝,問題出來了。
有一些 code,在不同版本、不同平台的 branch 重覆出現,小明資格老,做 Linux 時發現一些老問題,還會記得要抽空把在 Linux project 改的 code 給 merge 回 Solaris 和 Windows;但小美不熟 code 的典故,出了 XYZ for Windows version 1.1,卻想不到,這在 XYZ 2.0/3.0 Windows、XYZ 1.0 Linux and XYZ Appliance,通通需要 1.1 的 code。
當樹愈長愈亂,人們都在問,怎麼 XYZ 會愈做愈差咧?曾經修過的 bug,新版又出現;曾經加過的 feature,新版卻不見。小強每天道歉,不懂怎麼會錯誤連連;工程師們也很悶,明明知道 seamxr 說的對,code 寫好就要趕快 merge 回 main trunk,甚至不同平台就該同時設計一起做,但是盤根錯節的大樹已經長成,每個人只知道自己摸過的那個 branch,沒有人能 merge 回去,也沒有人敢砍掉重練。
寫這產品線大樹的故事,絕不是反對開 branch,我只是反省目前 project 最教我痛苦的事:花好多時間在各個 branch 裡爬行,就想搞清楚什麼該 merge、或不該 merge,但還是擔心會不會漏了什麼、又多了什麼。我們之所以開 branch,不是為了開出枝繁葉茂的大樹,而是要從 branch 回到 main trunk,也要定期從 main trunk 下到各個 branch。要減少同時開發/修改功能的混亂,更要讓彼此同步,而不是各自為政。
Branch,是為了要 Merge!
註:本文應作者以避免誤會為由要求,將標題中的Development Branch改為Release Branch。
本[網路部落格]文章僅反映作者個人意見,不代表ZDNET立場,並已獲作者同意以CC授權轉載。原文請見:作者部落格。
6.ChrisTorng 於 2008/07/31 11:07 回應
感覺牛頭不對馬嘴。原引文「Branch 不用錢,儘量開!」講的是每個人為自己的功能不要影響到他人,應該是 Development Branch,此文講的是為新平台、語言而開的分支,應該是 Release Branch。如果決策要為各種平台、語言釋出程式,那建立分支是必然的做法。比如說你的決策只做 Win/Linux 版本,並沒有要做 Mac 版本,那你就不可能無聊到建一個 Mac 分支。
每一個 Release Branch 都有它必須存在的理由。如果說怕它長太複雜,那應該是反省最初決策的必要性,是否需要為這個軟體支援那麼多種平台及語言。如果市場不夠大,人力不夠多,當然不應該釋出太多版本。如果決策確定沒問題,那每一個 Release Branch 都有它必須存在的理由。分支所帶來的複雜性也不可避免,只能盡力而為。
如果各 Release Branch 差異不大的話,也許只需要用條件編譯就可以建立多平台/語言版本,如此的話就不需要另開 Release Branch。或者差異可以全部集中在特定模組/類別/資源中的話,也可以全部放在主要 Branch 內,而在釋出版本時,運用不同編譯參數、Link 不同函式庫等方法,而達到一份原始碼可建立出多平台/語言的效果,如此也不必開 Release Branch。
因此,如果能用其他方法,避免 Release Branch 的話,那就用其他方法,不要開 Release Branch。
另外可以討論要不要開分支的空間,還是在原引文所講,是否每個人在開發新功能時,不要在主幹上直接改,而是開自己所屬的 Development Branch 在自己的環境裡改。在這種情況下,最極端應該是每個人都有自己的分支。
我個人並不贊同這樣的作法。
我的團隊目前做的是網站專案,因此並沒有需要跨平台,也沒有多語言的問題。
但還是有 Release Branch 存在,那是在每次釋出新版時,將測試資料庫連線字串改為上線資料庫、Debug 改為 Release 等,少數的修改。所以每一次釋出更新,都會有一個小 Release Branch 長出。如果沒有特別的意外的話,這種 Release Branch 只有一次分支,一次修改,不會繼續長大。
大家平時都直接在主幹上改。我是要求大家最少每天下班前,只要是能通過編譯的,沒有嚴重問題的,都要簽入。簽入前最好先取得最新版本再編譯測試一下就更保險。
由於一天內的修改有限,經常性的簽入,可以確保彼此的衝突範圍也很小,大家對今天的程式當然記憶猶新,任何衝突很快就能解決。
每次簽入後會自動建置,建置失敗會有通知,建置成功就自動部署到測試網站。其他測試人員可以在部署完成後收到通知,得知哪裡修正、新增了,並能立刻進行測試。
而不是等到幾個星期、幾個月後,功能全部完成了,全部簽入時,必須面對更複雜的衝突合併問題。如果一開始對需求與設計,彼此的溝通有誤解,這錯誤會到最終簽入後,才被別人發現,先前多時的工作豈不浪費?
因此,以我很有限的經驗來說,我會認為頻繁簽入,不開 Development Branch,會比各人開各自的 Development Branch 然後好久才簽入一次要來得好。
綜上所述,不管 Release Branch 或 Development Branch,都應該用盡各種方法避免才是。如是不可避免的,再另外想方法可以減少同步更新的麻煩與錯誤。
5.匿名 於 2008/07/25 00:12 回應
"各自為政、各人改各自的 code 而不溝通整合,那會讓 code 和人都愈來愈亂,變成更大的災難。"這樣的前提,即使從不Branch,在CHECK IN時,同樣的問題還是會發生。無關Development Branch 。
Development Branch 無罪啊•
4.ertjona 於 2008/07/22 17:32 回應
嘿!我的意思絕對不是 Development Branch 有罪!我想說的是,如果我們為了減少干擾混亂而開 branch,反而讓大家各自為政、各人改各自的 code 而不溝通整合,那會讓 code 和人都愈來愈亂,變成更大的災難。
謝謝大家的補充,謝謝!
3.匿名 於 2008/07/22 07:00 回應
回覆一樓誠如您所言,"問題是 A &B 雙方沒有坐下來, 重新定義那個程式應該怎麼設計."
Development Branch 無罪啊•
2.匿名 於 2008/07/22 06:56 回應
您的例子不是很好。支持不同的應用平台有不同的問題和挑戰。解決的主要方法是更好的設計和architecture。這好像說,所有醫生都是邪惡的,因為他們是無法治愈癌症。
Development Branch 無罪啊•
1.匿名 於 2008/07/21 18:27 回應
大家都知道要 merge, 但是同一個檔案有多人修改後. 就很容易產生 conflict. 問題是 A 改的, B 不一定懂, B 改的 A 也不一定懂. 最後不也常發生 A 改回他要的, B 的出問題. B 改成他要的, A 出問題.問題是 A &B 雙方沒有坐下來, 重新定義那個程式應該怎麼設計.
一直做 merge, 也無法完全修正問題. 除非問題被雙方提出來, 不然問題永遠都是自家內的問題. 只好改來改去.