摘要: 阿里有不少的研發團隊,不一樣事業部使用的發佈流程、分支策略並不是整齊劃一,但整體上看是比較規整的。其中有一種主流的發佈模式以及對應的分支使用方式,稱爲「AoneFlow」。這套工做模式思路獨特,在阿里之外的地方並很少見。本文圍繞這些實踐,聊一聊分支管理的話題。安全
引言運維
在阿里內部,流行着許多有意思的工程實踐。有些實踐經過工具和流程嵌在集團的大環境裏,外界不容易複製,有些實踐則是流露在你們的平常習慣裏,被默默的遵照。好比分支管理這件事,其實屬於工具和習慣各佔一半,而且很有阿里特點的成分,適合做爲一個例子。阿里有不少的研發團隊,不一樣事業部使用的發佈流程、分支策略並不是整齊劃一,但整體上看是比較規整的。其中有一種主流的發佈模式以及對應的分支使用方式,稱爲「AoneFlow」。這套工做模式思路獨特,在阿里之外的地方並很少見。本文圍繞這些實踐,聊一聊分支管理的話題。分佈式
細數分支模式微服務
說到分支管理模式,咱們最耳熟能詳的莫過於 TrunkBased 和 GitFlow。工具
TrunkBased 模式是持續集成思想所崇尚的工做方式,它由單個主幹分支和許多發佈分支組成,每一個發佈分支在特定版本的提交點上從主幹建立出來,用來進行上線部署和 Hotfix。在 TrunkBased 模式中,沒有顯性的特性分支。固然實際上 Git 的分佈式特徵天生容許每一個人有本地分支,TrunkBased 也並不是排斥短時間的特性分支存在,只不過在說這種模式的時候,你們一般都不會明確強調它罷了。測試
雖然近年來有許多不錯的案例,但 TrunkBased 模式並無一統天下。它的缺點比較明顯,太多的團隊同時工做在主幹上,到發佈的時候就可能出現災難(尤爲是多版本並行開發的狀況)。彌補的措施是 FeatureToggle 以及頻繁的集成和足夠的測試覆蓋,這對開發團隊的能力提出了比較高的要求。目前 TrunkBased 模式主要用在不須要同時維護多個歷史版本的 SaaS 型項目,特別是通過微服務改造的各類小型服務上。優化
TrunkBased 模式有兩種常見演進版本。OneFlow 模式參考了 TrunkBased 的許多思想,對操做流程作了更嚴格的定義,增長了 Hotfix 分支等內容。多主幹模式(一般是雙主幹,固定的開發分支和固定的發佈分支),算是 TrunkBased 採用固定發佈分支的特例,在提高團隊的微服務落地能力這篇文章裏介紹過,再也不贅述。插件
GitFlow 模式是若干模式的集大成者,包含一個主幹分支、一個開發分支、許多的特性分支、許多的發佈分支和 Hotfix 分支,以及許多繁瑣的合併規則。它有一個 Git 插件,不過早就沒人維護了。因爲對每一個階段的每項操做定義十分明確,它曾經是不少重視流程的企業眼裏的香饃饃。但它使用起來並非很容易,大量的合併衝突和對集成測試不友好也是它被詬病最多的地方。設計
對,還有 GithubFlow 模式,不過這種策略無非是在 TrunkBased 的基礎上,增長了我的倉庫和 Pull Request 合併代碼的操做,與在同一個倉庫裏增長我的分支的作法相似,從實用的意義來講,它更合適分佈式團隊。GithubFlow 也有演進版本,例如強調了多環境部署和將倉庫或分支與環境關聯的 GitlabFlow 模式。blog
要麼簡單粗暴如 TrunkBased,要麼繁瑣複雜如 GitFlow。難到真沒有其餘選擇了嗎?
另闢蹊徑的 AoneFlow
在 AoneFlow 上你能看到許多其餘分支模式的影子。它基本上兼顧了 TrunkBased 的「易於持續集成」和 GitFlow 的「易於管理需求」特色,同時規避掉 GitFlow 的那些繁文縟節。
看一下具體套路。AoneFlow 只使用三種分支類型:主幹分支、特性分支、發佈分支,以及三條基本規則。
規則一,開始工做前,從主幹建立特性分支。
AoneFlow 的特性分支基本借鑑 GitFlow,沒有什麼特別之處。每當開始一件新的工做項(好比新的功能或是待解決的問題)的時候,從表明最新已發佈版本的主幹上建立一個一般以feature/前綴命名的特性分支,而後在這個分支上提交代碼修改。也就是說,每一個工做項(能夠是一我的完成,或是多我的協做完成)對應一個特性分支,全部的修改都不容許直接提交到主幹。
規則二,經過合併特性分支,造成發佈分支。
AoneFlow 的發佈分支設計十分巧妙,可謂整個體系的精髓。GitFlow 先將已經完成的特性分支合併回公共主線(即開發分支),而後從公共主線拉出發佈分支。TrunkBased 一樣是等全部須要的特性都在主幹分支上開發完成,而後從主幹分支的特定位置拉出發佈分支。而 AoneFlow 的思路是,從主幹上拉出一條新分支,將全部本次要集成或發佈的特性分支依次合併過去,從而獲得發佈分支。發佈分支一般以release/前綴命名。
這條規則很簡單,不過實際的玩法就至關豐富了。
首先,發佈分支的用途能夠很靈活。基礎玩法是將每條發佈分支與具體的環境相對應,好比release/test分支對應部署測試環境,release/prod分支對應線上正式環境等等,並與流水線工具相結合,串聯各個環境上的代碼質量掃描和自動化測試關卡,將產出的部署包直接發佈到相應環境上。進階點的玩法是將一個發佈分支對應多個環境,好比把灰度發佈和正式發佈串在一塊兒,中間加上人工驗收的步驟。高級的玩法呢,要是按迭代計劃來關聯特性分支,建立出以迭代演進的固定發佈分支,再把一系列環境都串在這個發佈分支的流水線上,就有點經典持續集成流水線的味道了。再或者作一個將全部特性分支都關聯在一塊兒的發佈分支,專門用於對全部提交作集成測試,就玩出了 TrunkBased 的效果。固然,這些花哨的高級玩法是我臆想的,阿里的發佈分支通常都仍是比較中規中矩。
其次,發佈分支的特性組成是動態的,調整起來特別容易。在一些市場瞬息萬變的互聯網企業,以及採用「敏捷運做」的乙方企業常常會遇到這種狀況,已經完成就等待上線的需求,隨時可能因爲市場策略調整或者甲方的一個臨時決定,其中某個功能突然要求延遲發佈或者乾脆不要了。再或者是某個特性在上線前發現存在嚴重的開發問題,須要排除。按往常的作法,這時候就要來手工「剔代碼」了,將已經合併到開發分支或者主幹分支的相關提交一個個剔除出去,作過的同窗都知道很麻煩。在 AoneFlow 的模式下,重建發佈分支只是分分鐘的事,將本來的發佈分支刪掉,從主幹拉出新的同名發佈分支,再把須要保留的各特性分支合併過來就搞定。這一系列動做可以在很大程度上實現自動化,並且不會在倉庫留下一堆剔除代碼的記錄,乾淨無污染。
此外,發佈分支之間是鬆耦合的,這樣就能夠有多個集成環境分別進行不一樣的特性組合的集成測試,也能方便的管理各個特性進入到不一樣環境上部署的時機。鬆耦合並不表明沒有相關性,因爲測試環境、集成環境、預發佈環境、灰度環境和線上正式環境等發佈流程一般是順序進行的,在流程上能夠要求只有經過前一環境驗證的特性,才能傳遞到下一個環境作部署,造成漏斗形的特性發布流。阿里有統一平臺來自動化完成特性組合在發佈分支間的遷移,在下面講工具的部分裏會再介紹。
規則三,發佈到線上正式環境後,合併相應的發佈分支到主幹,在主幹添加標籤,同時刪除該發佈分支關聯的特性分支。
當一條發佈分支上的流水線完成了一次線上正式環境的部署,就意味着相應的功能真正的發佈了,此時應該將這條發佈分支合併到主幹。爲了不在代碼倉庫裏堆積大量歷史上的特性分支,還應該清理掉已經上線部分特性分支。與 GitFlow 類似,主幹分支上的最新版本始終與線上版本一致,若是要回溯歷史版本,只需在主幹分支上找到相應的版本標籤便可。
除了基本規則,還有一些實際操做中不成文的技巧。好比上線後的 Hotfix,正常的處理方法應該是,建立一條新的發佈分支,對應線上環境(至關於 Hotfix 分支),同時爲這個分支建立臨時流水線,以保障必要的發佈前檢查和冒煙測試可以自動執行。但其實還有一種簡便方法是,將線上正式環境對應的發佈分支上關聯的特性分支所有清退掉,在這個發佈分支上直接進行修改,改完利用現成的流水線自動發佈。若是非得修一個歷史版本的 Bug 怎麼辦呢?那就老老實實的在主幹分支找到版本標籤位置,而後從那個位置建立 Hotfix 分支吧,不過因爲阿里的產品大可能是線上 SaaS 業務,這樣的場景並很少見。
正是這些簡單的規則,組成了 AoneFlow 獨樹一幟的核心套路。
AoneFlow 中每個看似簡單的步驟都並不是憑空臆造,而是經歷大量產品團隊反覆磨礪後積累下來的經驗。接下來,我會說說 AoneFlow 的技術門檻以及阿里內部的應對之道。
AoneFlow 的體驗優化
諳熟武俠之道的人都懂得,掌握一個門派的看家武藝,除了要會招式,還得有深厚的內功和趁手的兵器。不然拿了辟邪劍譜,也只能望譜興嘆。
阿里團隊的內功和兵器,其實是良好的代碼習慣和齊全的配套工具。
這裏說的習慣,除了開發流程和代碼分支的管理方式之外,還包括平常開發中的一些約定俗成的規約。阿里的許多開發規約是有「文獻」記載的,主要收錄在 《阿里巴巴 Java 開發手冊》 裏面。它的內容如今已經公開了,因此早就不算是祕密。
舉一個具體的例子。在 AoneFlow 的流程中,每次重建發佈分支的時候都會從新合併而後編譯代碼,產生新的部署包。然而,即便代碼的內容是同樣的,若是工程中依賴了一些會改變的第三方軟件包,依然可能致使打包出的產品行爲不徹底一致。所以,在阿里的代碼規約中就明確地指出了,用於線上發佈的代碼,不可使用包含「SNAPSHOT 版本」(即未正式發佈版本)的依賴包,從而確保每次構建出的產物都是一致的。相似這樣的細節還有不少,好的開發習慣是確保軟件質量的必要前提。
工具可使得團隊協做更加平滑。雖然只要弄懂原理,AoneFlow 中每一個分支建立、合併、更改步驟使用單純的 Git 命令就能玩轉。但其中的一些操做(好比爲每一個發佈分支選出恰當的特性分支組合進行合併)手工執行極易出錯,並且讓團隊的我的重複這些平常雜事的命令操做,並非使人愉悅的事情。
在阿里內部,使用 AoneFlow 流程的團隊基本上不用本身運行 Git 來處理分支的事情,而是由阿里巴巴集團內部名叫 Aone 的協同研發平臺(如下簡稱平臺)接管。這個承擔集團 80% 產品從需求和用戶故事提出到部署上線完整研發流程的平臺,內置了許多以服務組件的形式嵌入的研發提效工具,其中的發佈組件爲 AoneFlow 的用戶體驗添色很多。比較顯著的輔助「功效」包括如下幾個方面。
首先是總體流程的自動化。
因爲是內部工具,平臺的功能高度內聚。對於項目而言,從提出原始需求,將需求拆分爲任務,而後根據任務在線建立特性分支,再聚合生成發佈分支,同時根據模板自動建立測試環境,直到後期的運維保障均可以一站式的搞定。
這個流程已經遠遠超出了代碼分支管理的範疇。但正是由於如此,平臺對於 AoneFlow,向前作到了將特性分支和需求項關聯起來,確保了特性分支的命名規範性;向後作到了將發佈分支與部署行爲關聯起來,確保了各環境版原本源的可靠性。打通了端到端交付的任督二脈。
其次是發佈分支的流水線。
做爲一種流程自動化的手段,CI/CD 流水線是許多現代交付團隊中常見的標配實踐。在 AoneFlow 的代碼生命週期裏涉及許多分支,當這些分支被建立或更新時,每每須要伴隨其餘的一系列行爲。流水線可以將這些平常開發過程當中的代碼分支與其所表達的深層意圖(好比提交代碼即進行集成測試)聯繫起來。特別是發佈分支,AoneFlow 的每一個發佈分支一般關聯具體的部署環境,當有新代碼合併進分支時,就應該及時對代碼進行檢查和部署。
理想狀況下,每條不一樣的分支都應該有與其做用相匹配的一條流水線來爲它服務。AoneFlow 的發佈分支是相對固定的,所以相比 GitFlow 更易於進行持續集成。理論上任何流水線工具都可以配合 AoneFlow 使用,不過,阿里的統一平臺提供流水線對代碼評審、安全檢查、在線部署等功能的整合,仍是爲 AoneFlow 在內部團隊的使用優化增色很多。
還有一項頗有用的輔助是分支關聯的管理。
特性分支與發佈分支的關聯關係維護是一個 AoneFlow 特有的問題。記住每一個發佈分支分別來自哪些特性分支對於須要基於現有特性組合進行改變的時候十分有意義。好比當須要將某個特性從特定發佈分支退出時,一般會將除了該特性之外的其餘特性所在分支進行一次合併,以替換原有的發佈分支。人爲的記錄這些信息並不輕鬆,要是經過平臺進行展現和輔助就會方便許多。
當某些功能組合在一個低級別的發佈環境(如集成測試環境)驗證完成後,咱們但願將它的內容直接遷移到高級別的環境(如預發佈環境)對應的發佈分支上。這樣能夠確保線上的版本必定是通過預發驗證的,預發的版本必定是通過集成驗證的,以此類推,使得各個發佈分支造成串聯。一樣的,使用普通的 Git 命令就能實現這個操做,只不過用可視化工具會讓流程更加直觀。
除此之外,平臺提供代碼倉庫各個分支情況的統一展現,包括分支所對應部署環境的機器信息、操做記錄等全都盡收眼底。正是這些「高附加值」的輔助,使得 AoneFlow 得以揚長避短,成爲阿里團隊支撐複雜項目首選的利器。
寫在最後
代碼分支模式的選擇並無絕對的正確和錯誤之分,關鍵是與項目的規模和發佈節奏相匹配。阿里協同研發平臺在通過衆多實踐歷練後,總結出了一套首創的分支管理方法,經過兼備靈活高效與簡單實用的流程,保障阿里旗下衆多產品的交付。當你還在猶豫於琳琅滿目的分支模式,既捨不得 GitFlow 的並行特性開發,又放不下 TrunkBased 的持續集成友好時,AoneFlow 也許是一個值得考慮的選擇。
閱讀更多幹貨好文,請關注掃描如下二維碼: