大型分散式團隊的程式碼版本管理

ThoughtWorks發表於2017-05-26

介紹這個話題,有兩個原因:

  1. 從開始工作到現在,我經歷過沒有程式碼版本管理、程式碼集中式管理,以及現在的分散式管理,我深刻體會到它在軟體開發過程中的重要性;
  2. 我在工作中遇到的很多客戶都存在對於程式碼版本管理的各種問題、困惑和不同的需求。

所以我希望將我在這個方面的經驗分享給更多人,希望能幫助更多的團隊解決在程式碼版本控制方面的問題和疑惑。

(圖片來自:http://t.cn/RSPnA5t)

一、程式碼版本管理系統的歷史

程式碼版本管理系統大致可以分為三個時代:

第一代:本地式

這代主要的特點提供原生程式碼版本控制,比如SCCS(1972)、 PVCS(1985)等。

這代主要實現了基本的程式碼版本管理,但缺點是無法讓多人同時對一個版本庫進行修改。這個也和當時軟體規模不夠大有關,也沒有這樣的需求。

第二代:客戶端-伺服器式

這代主要的特點是提供集中式伺服器端程式碼版本控制,比如 CVS(1986), ClearCase(1992), Visual SourceSafe(1994), Perforce(1995), Subversion(2000) 等。

這代主要是實現了中心伺服器端的程式碼版本管理,特點是可以讓多人同時對一個程式碼版本庫進行同步和修改,但缺點也相當明顯:

  1. 在無法連線伺服器的情況下,無法檢視日誌以及提交和比較程式碼版本(慢速網路和遠端異地工作的程式設計師的痛),以及當服務或者網路出現問題的時候很多人員就會無法工作。
  2. 不支援local branch,導致branch建立管理複雜,並且一旦建立就很難修改(快速迭代開發中的程式設計師的痛)
  3. 由於只有一箇中心端伺服器,一旦發生災難性問題,那麼所有日誌都會丟失,所以需要經常做備份(備份需要不小的成本)
  4. 如果軟體程式碼量過於龐大,一般會出現速度緩慢的情況,因為每次的日誌查詢、不同版本之間的程式碼比較和程式碼提交等操作都需要和伺服器通訊,造成伺服器端的負載過大。

第三代:分散式

這代主要的特點是提供分散式程式碼版本控制,比如Git(2005), Mercurial(2005)等。

這代結合了第一代和第二代的優點並實現了分散式的程式碼版本管理。

這代的優點:分散式管理,在沒有和伺服器有連線的情況下仍然可以檢視日誌,提交程式碼,建立分支;支援local branch,可以快速方便的實現各種分支管理;支援分散式,從而可以實現分塊管理,以及負載分流管理。

缺點是有一定的學習曲線,比如分佈方式下的程式碼同步,local branch的理解與運用,分散式程式碼管理的理解與運用等。詳細的比較可以參考:這裡

二、大型分散式團隊

曾經有這樣一個分散式團隊,他們在多個城市都有小分隊,並且正在開發一個大型專案,見下圖

他們使用的程式碼版本管理工具是第二代程式碼管理工具SVN,管理方案如下:

但是他們在使用的過程中卻遇到了下面這些問題與痛點。

由於是分散式團隊,所以:

  • 基於團隊的程式碼模組分離困難

當伺服器不可用時:

  • 不能檢視提交記錄
  • 不能比較檔案
  • 不能提交程式碼

建立程式碼分支時:

  • 分支建立速度慢
  • 多分支管理困難

在提交程式碼時:

  • 希望有Code Review
  • 希望有CI Review

因為程式碼龐大:

  • 檢視日誌慢

備份程式碼庫的時候:

  • 需要停機備份
  • 備份成本高

針對以上問題,可以使用新一代的分散式的程式碼版本管理系統來解決,見下圖:

其中每一個團隊都有自己獨立的程式碼庫,有一箇中心庫用於同步這些獨立的程式碼庫,並且每個庫都由團隊自己管理和維護。而且程式碼版本管理系統需要支援輕量分支,程式碼評審,離線提交,離線檢視日誌等功能。

但是由於當前沒有一個單一的程式碼版本管理工具能同時滿足以上所有需求,所以很多公司都基於它們開發整合管理系統,比如Gerrit,GitLab,GitHub,BitBucket等。其中的Gerrit由於其開源,免費,以及由Google開發和維護,並管理著Android,OpenStack等大型專案原始碼的特點,成為了大型分散式團隊優先選擇的系統。

三、Gerrit

Gerrit是由Google開發的,用於管理Google Android專案原始碼的一個系統。它是基於Java和Prolog等開發的,支援Git,許可權管理,程式碼評審等綜合的一個管理系統。它與GitLab和GitHub最大的不同是它隱藏了程式碼分庫管理的細節,使得開發人員不需要進行fork這樣的手工分庫和同步操作就可以進行程式碼開發和提交,節省了開發人員的時間,見下圖。

由於Android本身是一個開源專案,所以貢獻者非常多,開發團隊也遍佈多個地方(存在時差),導致“如何保證程式碼質量”成為一個很大的問題。為此Google在Gerrit中加入了功能強大並且十分嚴格的程式碼評審系統。

首先當程式碼提交以後並不會直接merge到中心庫裡面,它會暫時存在一個臨時庫裡面,同時生成一個程式碼評審記錄,並向特定的評審人員傳送請求評審的郵件。當評審者在評審程式碼之後,如果通過就需要在Gerrit系統裡面對程式碼進行打分,如果通過了就可以將程式碼merge到中心庫裡面去,如果沒有通過,那麼這個程式碼提交就需要被返還給開發者進行修改。

與此同時它還可以自動觸發一次包含本次程式碼提交的CI構建(前提需要手工預先配置),如果CI自動構建和測試通過,也可以自動在Gerrit系統裡面進行打分,可以給最終進行merge的人員進行參考。示意流程見下圖。

由於Android原始碼由上百個獨立的程式碼庫組成,並且編譯一個Android系統需要大部分程式碼庫裡面的程式碼,所以如何管理如此多的程式碼庫也是一個難題,比如如何一次性同步需要編譯一個需要支援特定裝置的程式碼庫組合。為此Google基於Python語言開發一個工具叫Repo ,這個工具可以自定義你需要的程式碼庫的組合,並且一次性對這些程式碼庫進行同步,比如pull和push,見下圖。

四、SVN到Git的遷移

對於想從集中式程式碼管理系統遷移到分散式程式碼管理系統的團隊來講,如果團隊規模小,那麼問題一般都不大,但是對於大型分散式團隊卻是困難重重。最主要的兩個困難:

  1. 程式碼量太大,很難一次性將所有的程式碼和日誌等在短時間內遷移成功。
  2. 由於下屬團隊太多,很難同一時間讓所有團隊都切換至新的程式碼管理工具。

為了解決這些難題,一般都會首先選用1個團隊來使用新的程式碼版本管理工具。如果這個團隊轉換成功,再將其作為標杆向其他團隊推廣,從而逐步的將所有團隊切換到新的工具上去。

SVN到Git的遷移方案一般主要會使用兩種工具:

  1. 開源免費的git-svn;
  2. 商業收費的Subgit。

其中使用Subgit的遷移方案如下圖:

如果團隊組資源充足,還可以使用Gerrit搭建一個獨立的Git伺服器,從而以分散式的方式進行程式碼遷移,如下圖:

五、多產品線的管理

使用同一個中心程式碼庫管理多產品線一直是大型專案的一個困難點,特別是使用SVN這樣的工具更是難以管理,因為SVN這種工具的Branch本質上是一個目錄拷貝,並且速度慢,而且程式碼回遷也需要手動進行。但是如果使用Git的特性來管理多產品線,比起SVN是事半功倍。具體方案見下圖:

總結:

分散式程式碼版本管理系統並不一定適合所有團隊,比如中小團隊可能更關心的只是成本更低,簡單易用,那麼SVN等這類集中式版本管理工具還是更為適合。但是不管團隊最終選用什麼程式碼版本管理工具,只要適合自己的團隊的開發流程和工作方式,並且程式碼管理順暢就可以了。

相關文章