標籤:
http://www.infoq.com/cn/articles/agile-version-control/
多個敏捷團隊之間的版本控制
如果我們有多個敏捷團隊在同一個程式碼程式庫上工作時,如何將彼此之間代碼互相衝突的風險最小化?如何確保每個迭代結束時擁有一個乾淨的、可發布的軟體版本?本文講述了關於如何在敏捷的環境中與多個團隊共同進資料列版本設定工作的執行個體——這正是我們在《Scrum and XP from the Trenches》中描述的公司所採納的方式。
本文並非專為版本控制專家所寫,實際上這樣的專家在本文中找不到新東西。本文是為我們這些希望進行簡單、有效協作的人所準備的。任何直接參与敏捷式軟體開發 (Agile Software Development)的人,無論他承擔何種角色,都有可能對其感興趣——每個人都會用到分支和合并,而不只是配置經理。
讀過本文之後,如果你需要一份文檔,請去目錄結尾處下載全文。
相關廠商內容
滴滴出行iOS用戶端架構演化之路!用戶端如何應對弱網路!函數式編程中的Swift與Swift中的函數式編程!AWS Webinar 5月24日線上課堂|利用AWS Lambda建立應用國際範 最前沿 不容錯過的容器技術盛會
相關贊助商
GMTC全球移動技術大會2016年6月24日-25日,北京,點擊瞭解詳情!
目錄
- 介紹
- 目標
- 單頁總結(可下載並掛在牆上)
- 版本控制模式
- 分支所有者&方針
- “完成”概念
- 何時建立額外分支?
- 從工作分支公開發布至主幹
- 如果團隊同時在實現多個故事該怎麼辦?
- 完成包括迴歸測試在內的工作
- 分叉代碼(合并衝突)
- 多個團隊——如果其他團隊同時向主幹中發布代碼該怎麼辦?
- 發布分支
- 大圖景
- 模型的變種
- FAQ
- 持續整合(CI)在這個模式中如何使用?
- 該版本控制模型使用哪種工具最合適?
- 與使用者故事無關的檢入怎麼處理?
- 合并代碼很麻煩,所以我想做得越少越好!
- 我還有更多問題!
- 參考資源
- 可下載的PDF
介紹
本文講述了關於如何在敏捷的環境中與多個團隊共同進資料列版本設定工作的執行個體。我假定你已經熟悉了Scrum的基本元素、XP方法和任務板。這些方式不是我發明的,它們是基於“主線(mainline)模型”或“穩定主幹(stable trunk)模式”。想閱讀更多資訊請查看引用部分。
撰寫本文,是因為我一直在遇到需要類似內容的團隊。許多團隊在理解了模型之後,似乎非常喜歡這些模型。它也正是我們在《Scrum and XP from the Trenches》中描述的公司所採納的方式。它真的可以協助我們以更敏捷的方式來開發和發布軟體。通過以易於閱讀的方式來描述模型,也許我不再需要反覆在白板前做解釋了。:o)
注意這隻是眾多模式中的一種,不是“銀彈“。如果你決定採用該模型,也許你需要做出一些變更來適應你自己的特定上下文。
目標
在多個團隊構成的敏捷環境中,版本控制模型必須達成以下目標:
- 快速失敗
- 代碼衝突和整合問題應該可以被迅速發現。
- 經常修複小問題要勝過不常修複大問題。
- 一直可發布
- 即使經曆了一個混亂的Sprint,也要保證至少有些發行就緒的內容。
- 簡單
- 所有的團隊成員每天都會使用這些模式,所以相關規則和程式必須要簡單明了。
單頁總結(對於掛在牆上的內容)
如果該圖讓你覺得很迷惑,別著急,閱讀本文即可。如果其中的理念對你來說很明顯,讀讀本文也無妨。
本總結也包含在可下載的pdf檔案中
版本控制模式分支所有者&方針
下面是要遵循的一條簡單規則。
規則:每個分支(即使是主幹分支)都擁有一個所有者和一條方針。
不遵守上述規則,我們只能得到一片混亂。方針說明按照本規則,什麼樣的內容可以檢入到當前分支中。所有者是負責定義和檢查規則執行情況的人。
“完成”概念
一個使用者故事怎麼樣才算“完成”?更明確地說,團隊什麼時候才可以把一個使用者故事移入到任務版上的“完成”一欄之中?這又到底意味著什嗎?
我會給出下面的假定。
假定:“完成”的定義=“可發布”。
所以當一個團隊成員說某個使用者故事已經“完成”,並將故事卡移入到“完成”一欄中之後,客戶就可以馬上跑到房間中說:“太好了!我們現在就上線吧!“,而且團隊中沒有人會說:“別,先等等。”
你可以使用任何你喜歡的“完成”的定義。但是要記得——如果定義中沒有完全包含“可發布”的含義,你就要好好想想了:在“完成”定義中沒有包含哪些內容?誰會來補齊這些內容?什麼時候?如果在“完成”之後出現問題,又會發生什嗎?
“完成”分支
當一個故事“完成”後,它需要有一個落腳之處。使用我的關於“完成”的定義(“可發布”),就意味著系統中的某個分支發行就緒,這樣該使用者故事對應的功能就可以進入到生產系統之中了。這就是“完成”分支。
任何分支都可以是“完成”分支。我將會使用主幹作為“完成”分支(這是一個不錯的開始)。有時這被成為“主線”。
假定:主幹作為“完成”分支。
主幹方針:
“任何時候都發行就緒”,這意味著:在任何時候,產品所有者都可以基於主乾的最新版本,發布新版本的產品。
下面是一個樣本。
藍色的線表示主幹。每個綠色的球形圖案表示一次代碼檢入活動。可以看到在本次Sprint中共檢入了5次內容。雖然通常我們是在每個Sprint結尾時才進行發布,不過還是可以在任何時候從主幹中發布產品。如果在接近Sprint結束時,有一半的團隊成員生病,因此導致沒有時間完成故事#5,我們還是可以進行一次發布。當然,我們也可以選擇先不發布,以等待團隊在另一個Sprint中完成故事#5。
“希望儘早發布”意味著如果我們不想讓某個故事相關功能上線(或者說不關心它是否上線),就不要檢入該故事相關的代碼。如果我不希望發布中的故事#3,這個分支就被我毀掉了。由於這個分支不再是可發布的,我就違反了分支的方針。
規則:不要在單一分支上合并不同的發布周期。
何時建立額外分支?
新分支的建立越少越好。下面是一條基於經驗的原則。
推薦:只在下面這種狀況下才建立新的分支:當需要檢入新的內容,而且沒有哪個現有的分支能夠在不違反自身方針的狀況下完成本次檢入。
工作分支
好,假設我們已經有了一個很好、很乾淨的主幹,並且在任何時刻都處於“可發布”狀態。
等一下。“可發布”意味著已完成整合測試。這就意味著我們必須要 運行整合測試。也就是說我們要在向主幹檢入代碼之前要運行整合測試。
那我應該向何處檢入我認為已經完成、但是在檢入主幹前需要進行驗證的代碼呢?當然,我可以在本機上完成測試,並直接將通過測試的代碼檢入到主幹之中。但這還是有點嚇人,我相信大家都遇到過“嘿,但是它在我的機器上運行沒有問題啊”這樣的事情。
另外一個問題是“好吧,我完成了今天的編碼任務,現在要回家了。我該把代碼檢入到哪裡?還沒有測試過呢,所以不能檢入到主幹中。我想把它檢入到別的地方,這樣其他的團隊成員就可以在其基礎之上繼續工作了”(敏捷團隊是採取代碼集體所有制的,對吧?)。
你看,我們有希望檢入的內容,但是不存在不違反分支方針就可以進行檢入的地方。這就是建立新分支的一個合理原因了。
我們可將此稱為工作分支,團隊所有成員都可共用該分支。有人稱其為開發分支。
團隊A的工作分支方針:
很好,現在我們有兩個分支了。一個穩定的分支(主幹)和一個稍微不那麼穩定的分支(團隊分支)。團隊分支是紅色的,表示它不太穩定;例如:這個分支通過了單元測試,但是它可能還沒有完成整合測試,所以還沒有穩定到發行就緒的狀態。好,現在團隊有地方可以檢入進行中中的工作了!
嗯,那要是需要同步不同的分支時應該怎麼做呢?往下看。
從工作分支公開發布(publish)至主幹
最終(我們希望)一個故事可以進入到“完成”狀態。或者更明確地說,最終工作分支會達到可發布狀態。此時我們可以(而且應該)將此分支公開發布到主幹上,比如將工作分支上所有的新代碼複製到主幹上。完成後,主幹與工作分支就完全相同了。
我們可以稱此過程為“公開發布”,因為我們已經完成了一些工作,而且現在已經準備好將其“公開發布”回主幹供發布用。這樣說只是一個有用的隱喻。
下面是一個樣本。假設我們已經實現了兩個故事:“開戶(Register)”和“存款(Deposit)”。它們都是“已完成”的,也就是說通過了單元測試、整合測試,並且處於“可發布”狀態。我們已經開始處理“取款(Withdraw)”這個故事,但是它還沒有“完成”。任務板看起來會像下面這張圖示一樣:
每個黃色的即時貼表示一項任務,也就是要完成故事需要做的一項工作。例如編輯類X,更新構建指令碼,等等。每項任務通常包含一個人日的工作,每個故事通常包含3至8個人日的工作。
分支的過程會像下面這樣:
我們的第一個團隊實現了“開戶”故事,並將代碼檢入到工作分支中,運行整合測試,修正一些問題,再次檢入,再次運行測試,通過了!“開戶”故事就“完成”了!然後將其公開發布到主幹之中。
接下來實現“存款”。只需要執行一次檢入就可以了。整合測試通過,我們再次把代碼發布到主幹之中。
現在團隊正在實現“取款”故事。他們已經完成兩次檢入了,但是這個故事仍然沒有完成。
注意“發布到主幹”並不是說我們僅把某個故事的代碼直接拷貝到主幹中,而是意味著所有的工作拷貝到主幹中,做一次完整的同步。
這樣就帶來了兩個很有趣的問題:
- 如果團隊同時在實現多個故事,該怎麼辦?
- 如果其他團隊也正在向主幹發布內容,又該怎麼辦?
我們還是一個接一個地來看這些問題。
如果團隊同時在實現多個故事該怎麼辦?
如果團隊每次實現一個故事,將代碼發布到主幹中並不算什麼大不了的事情。只要這個故事相關的代碼在工作分支上完成實現並通過測試,我們把所有的相關內容從工作分支上複製到主幹上就可以了。搞定!
先等一下。如果團隊中同時開發多個故事呢?如果“開戶”故事完成了,而“存款”還在進行中呢?
如果我們在這個點上向主幹進行同步,就會將尚未完成的“存款”故事同步進去,這時它還不能發布呢!而且違反了主乾的版本控制方針!
當然,我們可以等到“存款”故事完成。
(等待……)
好了,現在“存款”故事完成了!太棒了!等一下……現在有人開始開發“取款”使用者故事了!沒錯!同樣的問題又發生了!
如果 “存款”故事的一個測試失敗了,就很難知道是因為“存款”故事相關代碼造成的,還是由於檢入同一分支中並且部分完成的“取款”故事相關代碼的原因。
等待無法起到任何協助作用。這樣實際上是在滾雪球,期望在未來某個假設的時間點上所有的故事都可以完成(如果這樣的情況真的能夠發生的話),而且可以進行一次大規模的發布。
上述是一個非常普遍的問題。我們該怎麼做呢?
下面是一些應對之策:
- 不要做過多的並行開發。要力圖將團隊的注意力每次都只放在一個故事之上。
- 如果在“開戶”完成之前就有人準備開始“存款”相關的工作,要等到“開戶”徹底完成之後再檢入“存款”相關代碼。或者可以將“存款”相關的代碼檢入到一個臨時的分支之中,如果你喜歡操作多個分支的話。
- 如果在“開戶”完成之前就有人準備開始“存款”相關的工作,可以讓他先從一些相對安全和不可見的UI元素等部分開始,這些東西的變化不會影響到整個分支的可發布性。比如,“存款”需要開發一些新的代碼以及對一些舊有代碼的修改,可以先實現新的代碼(新的方法、新的類、新的測試等等),而不是先去修改已有代碼。如果“存款”需要新的GUI元素,那就讓它們先不可見。等到“開戶”故事完成而且發布到主幹上之後,我們就可以開始實現“存款”的剩餘代碼了。
下面是一個合適的規則集:
- 任何針對優先順序最高的故事開發的人都是“國王”。
- 團隊其他的任何人都是“僕人”。
- 要是你想成為“國王”,就試著找路子協助完成最高優先順序故事的相關工作吧。
- “國王”任何時候需要協助,“僕人”就必須馬上提供相應的服務。
- “僕人”不能打擾“國王”的工作。
- “僕人”不能向工作分支中檢入不可發布的代碼。“國王”可以檢入任何他想要檢入的東西(當然,只要他不違反分支方針即可)。
- 目前優先順序最高的故事一“完成”,任何開始下一個最高優先順序的團隊成員就成為了“國王”。
你甚至還能為團隊爭取到一些王冠飾品呢。:o)
總體來說,很多團隊都會過高評價同時實現多個使用者故事的效果。這樣做從開發速度上說感覺好像不錯,但卻只是一個幻象;因為它將有風險和消耗實踐的編碼工作推到了最後——包括合并、整合與測試等工作。
這就是Scrum團隊應該保持小規模的原因(少於9個人)——這樣他們就可以緊密協作而且將注意力集中於自己的工作成果之上。如果任何人都在獨立開發自己負責的使用者故事,那大概就不會有多少協作的情形發生了。當然可以有人為將來做計劃,為下一個故事做準備並做一些實現工作。但是在任何時候,團隊的主要工作努力都要放在優先順序最高的故事上。
多個團隊就是不同的情況了。如果很想並行實現多個故事,那就不妨建立多個團隊。我們不久後就會看到如何具體操作。首先我想討論下關於迴歸測試,以及分叉代碼的相關話題。
完成包括迴歸測試在內的工作
當一個故事“完成”後,我們會把它移入到“完成”一欄中,並將相關內容從工作分支拷貝到主幹中。主幹必須一直保持可發布狀態。此處有一個重要的暗示。
規則:任何接觸到主乾的人,必須保證整個主幹保持可發布狀態——包括之前的全部功能!
實際上,這條規則意味著:對故事A的測試,同樣包括運行之前實現的故事的全部相關迴歸測試。如果上傳代碼後,故事A沒有問題,但是之前故事的測試卻通不過了,這是不行的。
稍等。這是不是有點不合理啊?每完成一個故事就要運行所有的迴歸測試?
嗯,首先我沒有說運行所有的回顧測試。我是說所有相關的迴歸測試。我們已經有了一個乾淨而且可發布的主幹作為基礎,現在只是要添加一個故事而已!這是一個很小的增量變更。如果迴歸測試可以自動化完成,我們就可以全部運行了。要是有需要手工完成的迴歸測試,那我們就要有選擇性了。
最後還是歸結到了對風險vs成本的權衡之上。對於每一個手動的迴歸測試,我們應該評估運行它的成本(比如需要多少工作量來完成測試),同時評估發現任何重要缺陷的可能性,對二者進行權衡。當然還要加入自動化該測試的成本。:o)
分叉代碼(合并衝突)
假設我正在興高采烈地編寫調用Widget類的代碼,我卻不知道團隊成員Jim在一個小時之前進行重構時移除了Widget類。現在我們就有了< b>分叉代碼。在花費更多時間編寫其他調用Widget類的代碼前,我希望儘早發現類似問題。
規則:持續不斷地(等同於儘早)將你的代碼同步到工作分支中。
這種同步是雙向的。從工作分支中取得併合並最新的代碼,然後檢入你的代碼。第一步可以叫做“跟上”(等同於我要知道其他人檢入了哪些內容)。第二步可以叫做“公開”(等同於我希望我所做的更新可以讓團隊其他人都知道)。
每小時同步一次是好習慣,基本上在進行任務切換或者沒有處於某項工作進行中時,就可以進行同步。這不只是關於“我要儘快知道別人的代碼是否與我的相衝突”,還包括“我希望其他人儘快知道My Code是否與他們的衝突”。要記得不要違反工作分支的方針(通過單元測試等等)。
該規則聽起來很淺顯,但是請允許我不斷重申。我希望大家都能對其一清二楚,因為涉及到多個團隊協作時,我們會再次使用類似的思維方式。
多個團隊——如果其他團隊同時向主幹中發布代碼該怎麼辦?
假設有團隊A和團隊B。他們都是跨職能團隊,並且一起開發一個航班訂票系統。團隊A的注意力放在開發訂票流程之上,而團隊B主要負責開發後台相關功能。
假設他們現在要開始一個sprint,每個團隊有兩個使用者故事要開發(通常一個sprint中會有更多的故事)。
由於每個團隊都要在發布代碼到主幹前進行測試,因此他們有各自的工作分支。
現在我們遇到了一個有趣的問題。假定我在團隊A中,而且有我們自己的工作分支。變更可能先在主幹中發生,而不會先出現在我的工作分支中!為什嗎?恩,因為有另一個團隊啊,他們每完成一個故事就會將其發布到主幹中!
所以在任何給定的時刻,在主幹上都可能有我不知道的新代碼。而且這些代碼可能(但願不會如此)會與My Code衝突!也許團隊B中的某人會重新命名Widget類,可我已經在代碼中調用了它而且……呃……等一下,我們不是剛討論過這個話題了嗎?
沒錯,是同樣的問題。解決方案也相同。但是範圍有一點點不同。
規則:每天都從主幹向你的工作分支中合并代碼。
每天開始工作時,我所在團隊中的某人負責將代碼從主幹中合并到我們的團隊工作分支中(等同於“跟上”主幹中發生的變化)。
如果我的團隊(團隊A)發現一個代碼衝突,我們會馬上解決它——這是優先順序最高的事情!如果我們需要團隊B的協助(或者是開發與我們發生衝突的代碼的負責人),找他們過來,一起工作,把問題解決掉。重要之處在於我的團隊要負責解決問題,而且我們要在自己的工作分支上(而不是在主幹上)完成。
規則:在最不穩定的分支上解決衝突。
當然,如果人們不經常向主幹發布代碼,那從主幹合并代碼就是浪費時間了。除非有人發布工作到主幹上,團隊A和團隊B之間的任何分歧都會是不可見的。所以接下來的規則如下:
規則:經常從工作分支向主幹合并代碼,例如每完成一個故事之後。不要等到sprint結束後再做這個工作!
注意這裡有一個有趣的副作用:
副作用:先檢入代碼者為王!
如果兩個團隊正在開發的代碼互相衝突,後一個檢入的團隊必須負責解決衝突問題。這是一個好的副作用,因為它可以鼓勵團隊儘早檢入代碼。:o)
下面是一個完整Sprint的樣本圖:
兩個團隊進行了一次6天的sprint。團隊A準備實現“預訂”和“取消”。團部B準備實現“發票”和“黑名單”。讓我們看看發生了什麼。
| 天數序號 |
團隊A視角 |
團隊B視角 |
主幹視角 |
| 1 |
從主幹合并代碼。沒有新內容。開始開發“預訂”,將工作簽入自己的工作分支。 |
從主幹合并代碼。沒有新內容。開始開發“發票”,將工作簽入自己的工作分支。 |
今日無事發生。 |
| 2 |
從主幹合并代碼。沒有新內容。完成“預訂”的實現。通過整合測試。搞定了!複製到主幹。開始開發“取消”。 |
與昨日相同。 |
“預訂”現在完成了! |
| 3 |
從主幹合并代碼。沒有新內容。仍在開發“取消”。 |
從主幹合并代碼。啊哈!有變更了!添加了“預訂”相關的內容。在團隊B分支中合并我們的代碼,解決任何發生的衝突。然後繼續開發“發票”。 |
今日無事發生。 |
| 4 |
與昨日相同。 |
從主幹合并代碼。沒有新內容。完成“發票”的實現。通過(包括“預訂”在內的)整合測試,< font color="#008080">複製到主幹。開始開發“黑名單”。< /td> |
“發票”現在完成了!. |
| 5 |
從主幹合并代碼。啊哈!有變更了!添加了“發票”相關的內容。在團隊A分支中合并我們的代碼,解決任何發生的衝突。然後繼續開發“取消”。< /small> |
從主幹合并代碼。沒有新內容。仍在開發“黑名單”。 |
今日無事發生。 |
| 6 |
從主幹合并代碼。沒有新內容。完成“取消”的實現,複製到主幹. |
與昨日相同。 |
“取消”現在完成了! |
Sprint完成了!除“黑名單”之外,所有的故事都完成了。但是沒關係,我們還是發行就緒的!因為我們是以增量的方式完成合併與整合的工作。如果我們等到sprint結束再做,任何分叉的代碼就會在錯誤的時刻發現——此時我們能夠用來修複問題的時間最少。
發布分支
假定我們完成了sprint 1並發布了系統的1.0.0版本。現在,我們在進行sprint 2之中的工作時,有人報告說之前發布的版本中發現一個嚴重的缺陷!不!我們該怎麼辦?
最簡單的方式是:在主幹上修複該問題,並發布1.1.0版本。這就是說在sprint 2中任何新實現的故事都會包括在新發布版本中。理論上來說,這樣做沒有問題;因為主幹是“完成”分支,而“完成”的定義就是“可發布的”。所以主幹上的內容無論何時都是我們要發布的東西。
不過還是會有一些原因讓我們不想馬上發布新故事。例如:
- 發現了嚴重的缺陷,實質上意味著主幹在發布時就已經有問題了。也就是說sprint 2的故事都是在一個有問題的基礎上構建的。在必須處理新的故事之前,我們會想要修複這個基礎。
- 也許利益相關者不希望在sprint當中發布新的功能。
- 從主幹中發布包含新功能和全部已有功能的新版本,也許需要一段時間才能完成;所以我們需要一個“hotfix”機制來更快地修複問題。
我們具體該如何做呢?
- 建立一個名為“發布1.0”的發布分支,基於它在發布時的主幹內容。
- 在發布分支上針對缺陷打補丁。
- 在發布之後,馬上將發布分支合并到主幹之上(這樣補丁程式就會包含在未來的發布版本之中)。
注意我們在發布1.0.0版本時沒有必要建立“發布1.0”分支,可以等到問題出現時再做。這樣以來,除非真的需要建立某個分支以讓我們對其做些什麼,我們就不必建立額外的分支。
大圖景
好,現在我已經給出了如何使用該模式的詳細範例。讓我們往後站一點兒,看看整個的圖景是什麼樣子吧。
在主線模型中,一個分支被稱為一條代碼線(實際上,分支可以被人物是一條代碼線的實現)。有時這些被成為流。
一條代碼線的上級(也就是該代碼線的起原始碼線)被稱為它的基準。主線是沒有基準的代碼線。
所以在上面的例子中,我們可以總結出:
- 主幹是我們的主線。它不就是沒有上級嗎?
- 其他所有代碼線(發布版本1.0,團隊A的工作分支,團隊B的工作分支)都以主幹作為基準。
下面是一個更複雜的例子:
這個圖告訴我們:
- 項目X的代碼線衍生自主線。該項目目前已完成,所以分支就結束了。
- 團隊A有一個衍生自主線的活躍工作分支。
- 團隊A還有一個衍生自工作分支的、進行中中的Spike(譯註:Spike是指團隊集中精力在短時間內嘗試實現一個功能的活動。)。
- 發布版本2.3已關閉,因為2.3已經從生產系統中撤出而且不再會被維護。
每條代碼線有一個相對其基準的堅固水平,也就是說每條代碼線要不就比其基準更堅固,要不就不及其基準堅固(更柔軟)。
- 一條堅固的代碼線是穩定的,通過測試的,很少變更而且臨近發布。
- 一條柔軟的代碼線不穩定,很少測試,經常變更而且遠離發布。
在繪製代碼線時,堅固的代碼線分支向上,而柔軟的代碼線分支向下。觀察,我們可以總結出:
- 發布版本2.3比主線更堅固。
- 團隊A的工作分支比主線更柔軟。
- 團隊A的spike比團隊A的工作分支更柔軟。
使用上述描述繪製圖表,對於展示分支曆史來說很有用;但是如果同時有很多分支存在,就可能帶來混亂。下面是一個更清晰的格式,僅展示了當前存在的代碼線以及它們的衍生出處。
我建議以此格式繪製你的分支圖,而且可以將其掛到團隊所在房間的牆上。在討論整合問題時參考此圖真的很有協助。
所有的變更都應沿著所在的線索發展,這是一條很重要的規則!所以不能直接從團隊A的工作分支向團隊B的工作分支中合并代碼,這會導致很多混亂。實際上,在團隊A工作分支中發生的變更應該流回到主線中,再向下進入到團隊B的工作分支中。
任何位於主線之上的代碼線都可以稱為發布代碼線,意味著一個比主線更堅固的代碼線。
任何位於主線之下的代碼線都可以稱為開發中代碼線(或工作代碼線),意味著一個比主線更柔軟的代碼線。
協作黃金規則:
-總是接受穩定的變更。
-絕不強制使用會導致不穩定的變更。
那麼這對於不同類型的代碼線意味著什麼呢?
以彩色的方式說明了:
- 任何時候在發布代碼線上的變更,都應該立即合并到其基準中,並發布到主線上。
- 例:在2.4.2版本中修複了一個bug。這應該立即合并到2.4版本中,並將其合并到主線上。
- 一個發布代碼線永遠不要從其基準接受變更。
- 例:新的代碼檢入到主線中。該變更不應進入2.3版本和2.4版本。
- 變更應持續從基準流入到開發代碼線中。
- 例:任何針對主線的變更應該迅速向下流入到團隊A和團隊B中,並從團隊A向下流入團隊A的spike中。
- 開發代碼線的變更只有處於穩定點時才能發布到基準中。
- 例:團隊B只有在一個故事完成並通過測試後才能向主線合并變更。
無論變更何時應用到代碼線及其基準,有些合并是必須要做的。因為代碼合并是一個很容易犯錯誤的操作,我們希望在兩條代碼線中稍柔軟的一條上進行。一旦合并完成而且通過檢驗,我們就可以將合并的代碼複製回更堅固的代碼線。
將堅固代碼線比柔軟代碼線繪製得更高,使用這個慣例,我們可以推出一個簡單的規則:
規則: 向下合并,向上複製
樣本:團隊A注意到主線已經更新了。他們將變更向下合并到自己的開發代碼線,並修複任何衝突。只要團隊A的開發代碼線達到穩定的一個點,他們就可以將代碼複製回主線。當然,他們必須檢查同時主線上沒有發生任何變更。
模型的變種
“版本控制模式”一節描述了一個如何實施主線模型的範例。
“大圖景”一節以更通用的方式描述了主線模型。
本節中,我將針對如何實施該模式提出一些典型的變種。
“完成”的定義不必一定是“可發布的”。
先確定“完成”一詞的任何定義,然後確保有一個分支可以容納根據該定義已經“完成”的故事。不過還是要注意別遺漏重要的內容。如果整合測試沒有包含在“完成”中,那什麼時候進行整合測試呢?
主幹不必是主線
這個模式需要一條主線才能進行下去,不過不必是主幹(雖然在大多數情況下,使用主幹是很自然的選擇)。
團隊不一定必須有自己的分支
當然可以有多個團隊共用同一分支,甚至直接在主線上展開工作。只要保證遵循分支的方針即可。
通常,團隊希望有自己的分支,以避免未完成的故事在多個團隊之間造成幹擾。
不必每次都建立一個全新的發布分支
可以使用同樣的發布分支,而不是在每個sprint結束後都建立新分支。那個分支可以稱為“最新生產系統”或其他類似的名字。如果在生產系統中總是保持只有一個版本,這當然是很好的模型。
不必在每個sprint結束後都進行發布
可以在每個故事完成後進行發布。或者每三個sprint完成後發布一次。確定你自己的步伐。
不必針對每個故事都運行迴歸測試
如果在你的環境中,迴歸測試或整合確實很難實際操作,那麼可以在sprint接近尾聲時進行。這樣就可以針對一批故事進行測試和整合的工作。你自己要承擔相關風險。如果迴歸測試和整合屬於“完成”的定義,這可能意味著你在sprint末尾時可能會遇到問題,導致沒有任何故事完成的風險。
FAQ持續整合(CI)在這個模式中如何使用?
CI伺服器應該針對哪個分支運行?這要根據具體情況,不過下面的敘述是一個好的起點。
假定主乾的方針是“完成而且可發布”,而每個工作分支的方針是“通過單元測試”:
- 對每個工作分支來說,CI伺服器自動並持續地檢查構建和運行所有單元測試的狀況。
- 如果有任何失敗,就給出一個紅色警告。讓機器冒煙……
- 對每個工作分支來說,CI伺服器自動並有規律地(如果不能持續地)運行整合測試和迴歸測試。
- 如果有任何失敗,就給出一個分離的警告。因為這不是當前分支的方針。
- 當有人考慮從工作分支向主幹發布代碼時,要觸發該手工測試,以檢查故事是否“完成”。
- 對主幹來說,CI伺服器自動並持續地運行整合測試和迴歸測試。
- 如果有任何失敗,就給出一個紅色警告。讓機器冒煙、觸發警笛、USB火箭發射器,再把國民防衛隊叫來。
該版本控制模型使用哪種工具最合適?
不確定。我知道Perforce是可以的,我想subversion應該也沒有問題,但是對於CVS我不敢打包票。歡迎任何新的建議。
不過要記得一個重要的事情——切換工具的成本要比不能有效協作產生的成本低得多!所以搞清楚你想怎麼做,然後找到合適的工具來支援。
與使用者故事無關的檢入怎麼處理?
不是所有的代碼變更都必須與某個使用者故事相關的,在例子中,我只是為了描述的清晰才這樣做。無論檢入何種類型的代碼(或文檔之類),同樣的模型也是可用的。
合并代碼很麻煩,所以我想做得越少越好!
恭喜,你得了合并恐懼症——對於合并代碼的非理性恐懼!合并讓你覺得麻煩,是因為做的太少了。合并得越多,痛苦就越少。:o)
我還有更多問題!
看看後面的參考資源!我相信它們可以解決你大部分的問題。
查看英文原文:Version Control for Multiple Agile Teams
參考資源
如果你想瞭解更多,我強烈推薦下列資源。
《Practical Perforce》
作者Laura Wingerd。這是一個樣章,其中講述了主線模型的大部分內容。
這是一本關於Perforce的書,但是主線模型不僅限於Perforce。
《High level best practices in Software Configuration Management》
由Laura Wingerd和Chirstopher Seiwald合寫的關於版本控制的通用最佳實務的摘要,非常有用。
《Branching and merging – an agile perspective》
一篇由Robert Cowham所寫的、與本文主題有關的有趣文章。
《The Flow of Change》
又是由Laura Wingerd所作,對於主線模型的上佳摘要文章。“大圖景”一節中絕大部分內容基於這些投影片。
可下載的PDF
此處為 本文的pdf格式,可供下載。
關於作者
Henrik Kniberg是位於Stockholm的Crisp公司的一名諮詢師,專長於Java和敏捷式軟體開發 (Agile Software Development)。他建立了多個瑞典軟體公司,而且對於學習、講授和應用軟體開發的藝術充滿了熱情。Henrik從事了多種類型的工作,並喜歡扮演諸如經理、開發人員、Scrum Master、教師和教練等多種不同角色。Henrik是流行的InfoQ迷你書“Scrum and XP from the Trenches: How We Do Scrum”的作者。
多個敏捷團隊之間的版本控制