八馅闽、管理源代碼分支的模式(一)

一飘蚯、基本模式

1.1 Source Branching

Create a copy and record all changes to that copy.
源代碼管理系統(tǒng)記錄每一次提交的每個改變馍迄,讓代碼合并變得簡單,但不能讓代碼沖突消失局骤。如果兩個人同時修改同一個文件中的同一個變量定義攀圈,并且修改的值不一樣,那么源代碼管理系統(tǒng)在沒有人為干預(yù)的情況下就無法解決這個沖突峦甩。讓它更尷尬的是赘来,這種文本沖突至少是源代碼控制系統(tǒng)可以發(fā)現(xiàn)的,并提醒人們?nèi)ゲ榭囱ǖ辏€有一些沖突是合并時發(fā)現(xiàn)不了撕捍,但是系統(tǒng)就是不工作拿穴。比如泣洞,一個人改變了函數(shù)名稱,但另一個人還是引用的原來的函數(shù) 名稱默色,這就會導致語義沖突球凰。當這種情況出現(xiàn)時,系統(tǒng)可能會編譯失敗腿宰,也可能編譯成功但在運行時失敗呕诉。

image.png

大部分人會像上面那張一樣畫分支圖吃度,實際應(yīng)該時下面這張圖甩挫,隨著時間的推移變化會越來越大。
任何從事并發(fā)和分布式計算工作的人都對這種問題很熟悉间护。開發(fā)者并行更新同一個狀態(tài)亦渗。我們需要組合這些更改并序列化成一致的狀態(tài)。事實上汁尺,讓系統(tǒng)執(zhí)行并運行正確已經(jīng)越來越復(fù)雜了法精。這意味著對于共享的狀態(tài)有復(fù)雜的驗證標準。不可能創(chuàng)造一個確定的算法來達到一致痴突。需要人為的達到一致搂蜓,這個一致也許需要混合不同的更新。

1.2 Mainline

A single, shared, branch that acts as the current state of the product
mainline是一個特殊的分支辽装,代表的是團隊代碼的當前狀態(tài)帮碰。無論什么時候我想開始新的任務(wù),我就會將mainline克隆到本地開始工作如迟。無論何時我想和其他團隊分享我的工作收毫,我就會更新mainline*攻走,理想狀態(tài)是使用Mainline Integration 模式,稍后會講到此再。

不同的團隊對這個特別的分支取不同的名字昔搂。常常會鼓勵使用這個源代碼系統(tǒng)默認的。比如在git通常叫“master”输拇,svn通常叫“trunk”摘符。

必須強調(diào)的是mainline是一個單獨的、共享的分支策吠。當人們在git中談?wù)摗癿aster”時逛裤,他們可能表示的不同的東西,這是由于每個倉庫克隆有自動本地master猴抹。通常團隊有一個中心倉庫---一個共享的倉庫作為項目的單點記錄带族,也是所有克隆的原始副本。開始一項新的工作通常就是克隆中心倉庫蟀给。如果已經(jīng)克隆過蝙砌,當我開始工作時,我會先從中心倉庫拉取一份最新的跋理。這種情況下择克,在中心倉庫中mainline就是master分支。

當我開發(fā)一個新功能時前普,我會有一個自己的開發(fā)分支肚邢,這個分支就是我的本地master,或者我會創(chuàng)建一個單獨的本地分支拭卿。如果我在這個分支上開發(fā)了一段時間骡湖,我會不停的從mainline上拉取新的變更,然后合并到我的單獨的分支上记劈。

相同的勺鸦,如果我想為產(chǎn)品創(chuàng)建一個新的發(fā)布版本,我可以從當前的mainline開始目木。如果我想修復(fù)bug换途,可以使用Release Branch

When to use it

還記得在2000年的時候刽射,和一個工程師聊天军拟,他的工作是合并團隊開發(fā)的代碼。每次他會給團隊的每個成員發(fā)送郵件誓禁,然后成員會發(fā)送自己的代碼文件給他懈息。他然后拷貝這些文件和自己的代碼集成,然后編譯代碼庫摹恰。這通常會花費他幾周的時間辫继。

相反的怒见,通過mainline,任何人可以很快的使用最新的代碼開始工作姑宽。更進一步遣耍,mainline不僅讓當前代碼庫的狀態(tài)更易看見,也是我要講的其他模式的基礎(chǔ)炮车。

1.3 Healthy Branch

On each commit, perform automated checks, usually building and running tests, to ensure there are no defects on the branch

由于Mainline是共享的舵变、經(jīng)過驗證的狀態(tài),所以保持它在一個穩(wěn)定的狀態(tài)很重要瘦穆。

為了做到這一點纪隙,我們需要保證編譯都成功并且代碼沒有或者很少有bug出現(xiàn)。有以下經(jīng)驗可以借鑒:

通常測試要花費大量的時間扛或,所以可以使用 Deployment Pipeline將測試分成幾個階段绵咱。第一個階段需要盡可能地快,通常不長于10分鐘告喊,但仍要有測試力度麸拄。這一階段被稱為“commit suite”派昧,也叫做“單元測試(the unit test)”黔姜。

理想狀態(tài)下每一個提交都應(yīng)該觸發(fā)一次編譯。然后如果測試很慢蒂萎,比如是性能測試秆吵,那么這樣就不實用。

代碼運行沒有bug并不意味著就是好代碼五慈。為了保證交付地穩(wěn)定性纳寂,我們需要保證代碼地內(nèi)部質(zhì)量。一個常用地方法是 Reviewed Commits泻拦。

When to use it

每個團隊應(yīng)該在他們的開發(fā)流程中具有清晰的標準來保證分支健康毙芜,這具有巨大的價值。如果mainline健康争拐,一個開發(fā)者可以隨時開始工作只要拉取最新的分支即可腋粥。如果mainline不穩(wěn)定,需要花費大量的時間來修復(fù)分支問題架曹。

也要保證本地分支代碼健康隘冲,這樣就可以很容易合并到主干分支。

二绑雄、Integration Patterns

2.1 Mainline Integration

Developers integrate their work by pulling from mainline, merging, and - if healthy - pushing back into mainline
mainline表示了團隊軟件的當前狀態(tài)展辞。有mainline的一個好處就是簡化了集成。每個開發(fā)可以在自己本地分支上做集成万牺。

下面舉一個例子來說明罗珍,比如有個開發(fā)者叫小s洽腺,她要開發(fā)一個新的功能,用git將主干分支克隆到自己的本地倉庫:


image.png

當她在工作的時候覆旱,她的同事小V推送了一些變更到mainline已脓。由于小V在自己的分支上開發(fā),所以她并不知道mainline上的變動:

image.png

不久通殃,她想開始集成了度液。首先她要拉取mainline當前的代碼到本地,這會拉取到小V的變更画舌。由于她在本地倉庫上工作堕担,提交將在origin/master上顯示為一條單獨的代碼線。

image.png

如果小S幸運曲聂,合并小V的代碼沒有沖突霹购,否則就會有沖突需要解決。如果是文本上的沖突朋腋,源碼控制系統(tǒng)可以解決齐疙,但如果是語義上的沖突就很難解決。這時旭咽, Self Testing Code就非常有幫助贞奋。由于解決沖突會花費大量的時間,并且對代碼質(zhì)量也會產(chǎn)生風險穷绵,所以我將他們標記成黃色

image.png

這時轿塔,小S需要驗證她合并的代碼滿足mainline的健康標準。這通常意味著編譯代碼并運行所需要的測試仲墨。即使是沒有沖突的合并勾缭,也要進行編譯測試。任何提交中的錯誤都可能是由于合并導致的目养。知道這個可以幫忙她定位問題俩由,至少首先應(yīng)該從合并代碼中找到線索。

通過這種編譯和測試癌蚁,她成功地將mainline的代碼合并到自己的代碼庫幻梯,但是她還沒完成和mainline的集成。為了完成集成匈勋,她必須推送她的變更到mainline礼旅。集成包括拉取和推送。只有她完成推送后洽洁,她的工作才能開始和其他項目集成痘系。

image.png

2.2 Feature Branching

Put all work for a feature on its own branch, integrate into mainline when the feature is complete.

使用功能分支,開發(fā)者在開發(fā)一個功能特性時打開分支饿自,然后持續(xù)在這個分支上工作直到完成汰翠,最后集成到mainline龄坪。

例如,還是以小S為例复唤,她開發(fā)一個新功能:添加本地的銷售費率到他們的網(wǎng)站健田。她以當前產(chǎn)品的穩(wěn)定版本開始,拉取mainline到自己的本地佛纫,然后以當前mainline為基礎(chǔ)創(chuàng)建一個新的分支妓局。她以后一直在這個分支上開發(fā),提交了很多代碼呈宇。


image.png

She might push that branch to the project repo so that others may look at her changes.
她也可以推送這個分支到遠程倉庫好爬,這樣別的開發(fā)者也可以看到她的變更。
當她工作的時候甥啄,其他提交會在mainline存炮。所以時不時的,她會從mainline拉取新的代碼蜈漓,這樣就可以知道有哪些改變會影響她的功能穆桂。


image.png

需要注意到這并不是我上面描述的集成,是因為她并沒有推送回mainline融虽。這時她只能看到她自己的工作享完,其他人的看不見。

一些團隊喜歡讓所有的代碼都保存在遠程倉庫衣形。這時候小S就必須推送她的分支到遠程倉庫驼侠。這也允許團隊中的其他成員可以看到她當前的工作狀態(tài),即使還沒和其他人的代碼集成谆吴。

當她完成自己的功能開發(fā)時,她會執(zhí)行 Mainline Integration 來合并這個功能到產(chǎn)品中苛预。

image.png

如果小S在開發(fā)多個功能特性句狼,那么她可以為每個功能創(chuàng)建獨立的分支。

When to use it

Feature Branching在當今的工業(yè)生產(chǎn)中是一種很受歡迎的模式热某。為了談?wù)摵螘r用它腻菇,我需要介紹它的主要的替代方法- Continuous Integration。但是首先需要談?wù)擃l繁集成的作用昔馋。

2.2.1 Integration Frequency

集成的頻繁程度對一個團隊運作有很大的影響筹吐。來自State Of Dev Ops Report 的調(diào)查研究表明精英開發(fā)團隊比低績效開發(fā)團隊更頻繁的集成。這個調(diào)查符合我和大多數(shù)同行的經(jīng)驗預(yù)期秘遏。

Low-Frequency Integration

以low-frequency 案例為例丘薛,開始講述。還是以小S和小V為例邦危,她們各自開始自己的工作洋侨,拉取mainline到自己的分支舍扰,然后做了一些變更但還未提交


image.png

他們工作時希坚,其他人提交了一個變更到mainline:


image.png

這個團隊通過保證分支健康來工作个束,每次提交都會拉取mainline聊疲。小S前兩次提交沒有拉取mainline是由于mainline未發(fā)生變更售睹,但是現(xiàn)在她需要拉取M1:


image.png

我將這次merge用黃色方框表示昌妹。這次merge提交S1..3到M1飞崖。不久小V也需要做同樣的事情:


image.png

這時兩位開發(fā)者都和mainline保持同步蒜鸡,但是她們之間還未集成逢防,因為代碼都是隔離的忘朝。小S無法察覺到小V的V1..3做的變更局嘁。

小S又做了兩次提交悦昵,然后準備向mainline集成但指,這次合并很容易枚赡,因為她已經(jīng)拉取了M1的變更。

image.png

然后,小V就會有一個更復(fù)雜的體驗疲迂。當她集成到mainline時莫湘,她不得不集成S1..5到V1..6腰池。


image.png
High-Frequency Integration

在前面的例子中示弓,兩位開發(fā)者做了很多次提交后才開始集成奏属。讓我偶們看看如果每次提交就和mainline集成會發(fā)生什么囱皿。

小V第一次提交后就和mainline集成嘱腥,此時集成很容易爹橱。


image.png

小S第一次提交后也和mainline集成,但因為小V已經(jīng)提交了椭盏,所以她需要做一次merge掏颊,但由于只需要merge V1和S1,這次合并的代碼量很少盆偿。

image.png

小S的下一次集成只需要推送代碼就行了,這意味著小V的下次提交要合并小S的最近兩次提交求橄。然后罐农,這仍然是一個相對較小的merge涵亏。


image.png

當有其他人推送代碼到mainline時,小S和小V只需要按照以往的節(jié)奏合并代碼即可裆悄。


image.png

和之前一樣光稼,這次小S只需要集成S3和M1艾君,因為S1和S2已經(jīng)集成過。這意味著小G在推送M1的時候不得不集成S1..2虹茶,V1..2蝴罪。

開發(fā)者繼續(xù)剩下的工作要门,每次提交都集成:


image.png
Comparing integration frequencies

讓我們來看看上面兩種方式的區(qū)別


image.png

這里有兩個明顯的不同封豪。第一就如high-frequency integration名字所表示的那樣润脸,它比 low-frequency integration多很多次旷太,而且更重要的是每次合并的代碼量很少处嫌。越小的集成意味著越少的工作量斩个,因為沖突越少。比工作量少還要重要的是做个,風險也少了滚局。大合并的問題不在于工作本身,而在于工作本身的不確定性太闺。

大多數(shù)時候省骂,即使是大型合并也會進展順利最住,但偶爾也會進展得非常非常糟糕。偶爾的疼痛會比一般的疼痛更嚴重涨缚。如果我比較花費額外的10分鐘每個集成與1 / 50的機會花費6小時修復(fù)一個集成-我更喜歡哪一個。如果我只看努力程度兰吟,那么1 / 50更好,因為是6小時而不是8小時20分鐘茂翔。但這種不確定性讓50%的人感覺更糟揽祥,這種不確定性導致了對融合的恐懼。

我們從另一個角度來看一看兩者之間的差別檩电。如果小S和小V在第一次提交時就出現(xiàn)沖突會發(fā)生什么。在low-frequency場景下,他們直到小V的最后一次merge才會發(fā)現(xiàn)這個沖突俐末。而在high-frequency 場景下料按,在小S第一次提交時就會發(fā)現(xiàn)。


image.png
image.png

頻繁的集成增加了合并的頻率但也減少了復(fù)雜性和風險卓箫。頻繁的集成還能更快地提醒團隊發(fā)生沖突载矿。這兩者是有聯(lián)系的。令人討厭的合并通常是團隊工作中潛在的沖突的結(jié)果烹卒,只有在集成發(fā)生時才會浮出水面闷盔。

很多人沒有意識到的是源碼控制系統(tǒng)是一個交流工具逢勾。它可以讓一個開發(fā)者知道其他人正在做的事情迫摔。通過頻繁的集成纱烘,不僅可以立即知道代碼有沖突啤它,也可以知道每一個人的最新開發(fā)進展塌碌,以及代碼庫是如何演進的。我們不是孤身一人而是作為一個團隊在一起工作懊缺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖涕刚,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盼樟,死亡現(xiàn)場離奇詭異击碗,居然都是意外死亡,警方通過查閱死者的電腦和手機验夯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門借宵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欲间,“玉大人嘱能,你說我怎么就攤上這事右冻。” “怎么了纱扭?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長因惭。 經(jīng)常有香客問我乒躺,道長设拟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮核行,結(jié)果婚禮上牢硅,老公的妹妹穿的比我還像新娘。我一直安慰自己芝雪,他們只是感情好减余,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惩系,像睡著了一般位岔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蛆挫,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天赃承,我揣著相機與錄音,去河邊找鬼悴侵。 笑死,一個胖子當著我的面吹牛拭嫁,可吹牛的內(nèi)容都是我干的可免。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼做粤,長吁一口氣:“原來是場噩夢啊……” “哼浇借!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怕品,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤妇垢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肉康,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闯估,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年吼和,在試婚紗的時候發(fā)現(xiàn)自己被綠了涨薪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡炫乓,死狀恐怖刚夺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情末捣,我是刑警寧澤侠姑,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站箩做,受9級特大地震影響莽红,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卒茬,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一船老、第九天 我趴在偏房一處隱蔽的房頂上張望咖熟。 院中可真熱鬧,春花似錦柳畔、人聲如沸馍管。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽确沸。三九已至,卻和暖如春俘陷,著一層夾襖步出監(jiān)牢的瞬間罗捎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工拉盾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留桨菜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓捉偏,卻偏偏與公主長得像倒得,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子夭禽,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 現(xiàn)代的源代碼控制系統(tǒng)提供了強大的工具霞掺,可以非常輕松的在源代碼上創(chuàng)建分支。但最終分支還是要合并在一起讹躯,許多團隊不得不...
    暴走的初號機閱讀 1,300評論 0 0
  • 原文:https://martinfowler.com/articles/branching-patterns.h...
    林萬程閱讀 364評論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理菩彬,服務(wù)發(fā)現(xiàn),斷路器潮梯,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 在軟件工程中酷麦,集成是一個漫長而又不可預(yù)測的過程矿卑。因此一些公司開始嘗試讓團隊中的成員每天集成一次,這樣開發(fā)者不會偏離...
    bylaw閱讀 789評論 0 0
  • 簡介 現(xiàn)代軟件開發(fā)過程中要實現(xiàn)高效的團隊協(xié)作沃饶,需要使用代碼分支管理工具實現(xiàn)代碼的共享母廷、追溯、回滾及維護等功能糊肤。目前...
    Lucas66閱讀 8,191評論 0 5