我還沒(méi)有見(jiàn)過(guò)比源碼版本操縱 這樣跨任意編程語(yǔ)言更基本的工具。 這是我們用過(guò)的最基本的工具,是很多開(kāi)發(fā)團(tuán)隊(duì)的生命線。 那么,為什么我們經(jīng)常會(huì)用錯(cuò)呢? 為什么一些真正的核心,版本操縱 系統(tǒng)的基礎(chǔ)往往知之甚少?
我總結(jié)了10個(gè)實(shí)踐 或“戒律” - 這通常是發(fā)生故障或錯(cuò)誤理解的開(kāi)始, 是與版本操縱 產(chǎn)品和編程語(yǔ)言無(wú)關(guān)的。 我會(huì)從Subversion和.NET挑選一些例子,但它們廣泛適用于其他技術(shù)。
1。 如果還在使用VSS,馬上停手
平心而論,在1995年VSS曾是一個(gè)偉大的工具。 不過(guò)因?yàn)橛辛讼馭ubversion甚至分布式的如Git和Mercurial工具變得黯然失色。 很多年前微軟已經(jīng)明確表明廢棄它了!
由于一系列的重大缺陷,VSS曾受到廣泛的幾乎一致的鄙視, 俗稱為微軟的源代碼破壞系統(tǒng) 。
2。 如果源代碼沒(méi)有處在版本操縱 ,那等于還沒(méi)有
每天重復(fù)此咒語(yǔ) - “進(jìn)步的唯一標(biāo)準(zhǔn)是工作代碼處在源代碼操縱 中”。 直到你的成果出現(xiàn)在源代碼操縱 里 - 變成源操縱 庫(kù)中的項(xiàng)目 - 否則它根本不存在。
當(dāng)然,你已經(jīng)把代碼做好在本地計(jì)算機(jī)上的某個(gè)地方,但,對(duì)其他人來(lái)說(shuō)這不是真的做好了,對(duì)嗎? 他們不能拿到你的版本,他們不能合并他們的修改,你無(wú)法部署它(除非你部署出錯(cuò) ),一旦發(fā)生硬盤(pán)損壞你將永久丟失這些文件。
你要保持除非提交否則根本還沒(méi)有的心態(tài),一大堆的其他良好的運(yùn)作因?yàn)闆](méi)有提交開(kāi)始陷入困境。 你應(yīng)將任務(wù)分解成更小的單位,這樣你可以原子地提交。 您應(yīng)頻繁地整合,保證自己不受本地硬件故障的影響。
但更重要的是(至少對(duì)你的團(tuán)隊(duì)領(lǐng)導(dǎo)來(lái)說(shuō)),你證明你實(shí)際做了東西。 燃盡圖曲線下降或分解列舉任務(wù)列表是很棒的,但他們真的順暢嗎? 除非這些與工作源碼操縱 中的工作代碼關(guān)聯(lián)上,他們才意味著完成。
3。 盡早提交,頻繁提交,越快越好
繼續(xù)上一點(diǎn),只有這樣,才能幸免“幽靈代碼” -那些只有你可以在你本地計(jì)算機(jī)上能看到的代碼-要盡快地盡早地頻繁提交到VCS版本操縱 系統(tǒng)里 。 上面提到的是應(yīng)盡早和經(jīng)常的完成提交,但其中有幾點(diǎn)可以使你的工作方式有意義:
1,每個(gè)提交的修訂版能給你一個(gè)回退的位置。如果你完全搞砸了,你想回滾一個(gè)小時(shí)的變化還是一個(gè)星期的嗎?
2,合并噩夢(mèng)的風(fēng)險(xiǎn)不會(huì)顯著增加。合并從來(lái)就沒(méi)有樂(lè)趣。 當(dāng)你幾天沒(méi)提交代碼時(shí),你突然發(fā)現(xiàn)到你已經(jīng)與其他人的變化有50個(gè)沖突,你肯定不開(kāi)心。
3,它會(huì)強(qiáng)迫你將功能隔離在分散的工作單元。比方說(shuō),你已經(jīng)有了一個(gè)3人天功能需實(shí)現(xiàn)。 通常,因?yàn)樗麄兿朐噲D整個(gè)地構(gòu)成一個(gè)邏輯單元直到這段時(shí)間結(jié)束才提交。 當(dāng)然,像這樣大的一個(gè)任務(wù)不可幸免地由小規(guī)模,分散的功能組成,頻繁提交迫使你識(shí)別這些原子小任務(wù),然后逐一地完成它們提交給VCS。
當(dāng)你以這種方式工作時(shí),你的提交歷史形成一個(gè)有規(guī)律的模式,每天多次提交。 當(dāng)然,并不總是保持這樣不變的模式,有時(shí)我們停止開(kāi)發(fā)和重構(gòu)進(jìn)入測(cè)試階段,或任何其他中斷正常的開(kāi)發(fā)周期的活動(dòng)。
然而,當(dāng)我看到一個(gè)獨(dú)特的 - 甚至整個(gè)項(xiàng)目,在一個(gè)正常的開(kāi)發(fā)周期,有整天甚至很多天什么沒(méi)提交,我很擔(dān)心。 我很擔(dān)心是因?yàn)楦鶕?jù)之前提到的,沒(méi)有可衡量的工作已經(jīng)完成,但我也很擔(dān)心,因?yàn)檫@通常意味著出問(wèn)題了。 這意味著,開(kāi)發(fā)像“沸騰的海洋”那樣進(jìn)行(例如,試圖一次做所有事情),或根本沒(méi)有任何價(jià)值的事情在發(fā)生,因?yàn)樵谒械娜硕级氯? 在一個(gè)問(wèn)題上。 無(wú)論哪種方式都是錯(cuò)的,源代碼操縱 系統(tǒng)正打了個(gè)大紅色警告。
4。 在提交之前,請(qǐng)務(wù)必檢查您所做的更改
提交代碼到源代碼操縱 系統(tǒng)是很容易的 - 太容易了!無(wú)論如何,你總算了結(jié)了變更和提交了文件。 “在項(xiàng)目的根目錄有一個(gè)變更地方 - 快 - 提交了!”
可能會(huì)發(fā)生一件或兩件事情:首先,人們?cè)诓唤?jīng)意間上傳了一大堆的垃圾文件到存儲(chǔ)庫(kù)中。 請(qǐng)看類似下面的窗口,點(diǎn)擊“全選”和確定 - 庫(kù)不應(yīng)該被某些文件如調(diào)試Debug文件夾和其他垃圾污染了。
其次,提交文件經(jīng)常不檢查他們實(shí)際上已經(jīng)改變什么。 例如在本地開(kāi)發(fā)一次性修改的配置或項(xiàng)目定義文件,這使得它很容易在不經(jīng)意間被放到資料庫(kù),原本不打算提交的,當(dāng)然,他們很可能被其他開(kāi)發(fā)者獵取 。 你真的能記住你改變了這個(gè)配置文件中的東西嗎?
解決方法很簡(jiǎn)單: 在提交之前你必須檢查每一個(gè)變化 。 這聽(tīng)上去很容易,可使用很多版本系統(tǒng)實(shí)現(xiàn)的“忽略”功能,在很大程度上緩解“無(wú)意中提交文件”問(wèn)題。 你不想提交Thumbs.db文件,只要忽略它,還有 你可能不想要提交的每一個(gè)變更文件!
你經(jīng)常想知道文件哪個(gè)地方修改了,為什么又提交Web.config文件?你可以使用VCS的文件比較Diff功能。
啊,我現(xiàn)在想起來(lái),我想減少最大無(wú)效密碼嘗試從5下降至3。 哦,我玩了一個(gè)假的登錄頁(yè)面,我絕對(duì)不希望提交到庫(kù)中。
5。 記得提交時(shí)編寫(xiě)提交信息日志,
有了提交日志信息,我可以理解你的提交信息并可通過(guò)你的代碼試圖追蹤一個(gè)錯(cuò)誤。
提交信息的整體思路是解釋為什么你提交代碼,每次你改變代碼,肯定是有原因的。 也許是出了故障, 也許顧客不喜歡配色方案。 也許你只需要調(diào)整build配置。 不管它是什么,它是有原因的,你需要在你提交后留下它。
為什么要寫(xiě)日志呢? 根據(jù)上下文的不同有幾個(gè)不同的原因, 例如,使用“責(zé)備”功能,或其他類似的功能,它暴露了誰(shuí)改變了什么以及意圖 。 我不記得我在18個(gè)月前對(duì)這個(gè)項(xiàng)目中的Web.config改了什么,為什么我修改應(yīng)用程序設(shè)置,因?yàn)槲伊粝铝瞬诲e(cuò)的提交信息,這一切都變得非常簡(jiǎn)單:
同樣地,隨著時(shí)間的推移變化,無(wú)論我是否希望看到的一個(gè)文件全部歷史記錄,如下圖,我只是想看看昨天整個(gè)團(tuán)隊(duì)完成了什么,如有記錄描述性的意見(jiàn),意味著不需要采取更仔細(xì)的研究,就能了解這是怎么回事。
最后,提交的信息是絕對(duì)無(wú)價(jià)的,當(dāng)涉及到跟蹤錯(cuò)誤。 例如,想知道什么打斷了持續(xù)集成環(huán)境。 當(dāng)然,我的例子是明顯而易見(jiàn)的,但有一點(diǎn)是,如果沒(méi)有這個(gè)信息,這將是個(gè)棘手的問(wèn)題。
進(jìn)一步考慮一下,這里有一些提交信息的反模式:
1.有些事情。
2.它的工作原理!
3.修正了一些該死的錯(cuò)誤
4.修復(fù)
5.修正一個(gè)小錯(cuò)誤...
6.更新
7.錯(cuò)字
8.修訂1024!
我是從Stack Overflow上問(wèn)題挑選出來(lái)的——你曾經(jīng)編寫(xiě)的最糟糕的提交信息是什么。 他們沒(méi)有告訴你代碼中實(shí)際發(fā)生了什么,他們是垃圾信息。
關(guān)于提交信息的最后一件事, 來(lái)自同一作者的隨后提交的信息不應(yīng)該是相同的 。 原因很簡(jiǎn)單:你正在提交的原因與上一個(gè)版本不同。 你的代碼與先前的版本是在一個(gè)不同的狀態(tài),如果你提交的信息是準(zhǔn)確和完整的,應(yīng)該在邏輯上是不相同的。 此外,如果是相同的(也許有一個(gè)合法的邊緣情況下),日志變亂了,沒(méi)有辦法辨別兩次提交之間的差異。
6。 您必須自己提交更改 - 不能委派
這聽(tīng)起來(lái)很奇怪的,因?yàn)?,它發(fā)生過(guò),我見(jiàn)過(guò)不止一次,最近一次就在上周。 這里的情況是源代碼操縱 庫(kù)被放置在操縱 臺(tái)機(jī)器上。 由于種種原因,該團(tuán)隊(duì)將其視為隔離,完美的代碼純凈環(huán)境。 為了維持這個(gè)神圣的狀態(tài),代碼提交之前需經(jīng)過(guò)小組評(píng)審并(推斷)調(diào)整和改進(jìn)后才能被首席開(kāi)發(fā)人員提交。
似乎這種模式是很有道理的。 但極少提交,多個(gè)開(kāi)發(fā)人員團(tuán)隊(duì)只有一個(gè)作者,如果長(zhǎng)時(shí)間沒(méi)有提交的任何人一旦離開(kāi)了即無(wú)可幸免地將造成沖突混亂, 這樣非常危險(xiǎn)。
有兩個(gè)重要的事情錯(cuò)在這里:第一源代碼操縱 并不意味著是無(wú)暇的,無(wú)問(wèn)題的原始代碼;第二沒(méi)有貫穿整個(gè)開(kāi)發(fā)周期。 源代碼庫(kù)是團(tuán)隊(duì)整合頻繁的地方,當(dāng)出錯(cuò)時(shí)可回滾,團(tuán)隊(duì)工作圍繞的一個(gè)共同的基礎(chǔ)。 在整個(gè)過(guò)程中并不一定是完美的,但它必須(嘗試)在應(yīng)用程序生命周期中的達(dá)成公布狀態(tài)。
另外,從開(kāi)發(fā)者的角度來(lái)看, 這種模式是根本沒(méi)有源代碼操縱 !這意味著沒(méi)有和同行集成代碼,沒(méi)有回滾,沒(méi)有日志,什么都沒(méi)有! 你只是坐在那里,在你的本地寫(xiě)代碼,等待未來(lái)的任意點(diǎn)手工傳給老板。
7。 數(shù)據(jù)庫(kù)版本操縱 不是可選的
這是每個(gè)人都應(yīng)該知道的,但很多時(shí)候,他們就是由于“很難”而沒(méi)有做操縱 。 問(wèn)題是,許多(大多數(shù)?)的應(yīng)用程序沒(méi)有數(shù)據(jù)庫(kù)將無(wú)法運(yùn)行。 如果你沒(méi)有版本操縱 數(shù)據(jù)庫(kù),那么最終是一個(gè)不完整的應(yīng)用程序。
大多數(shù)VCS系統(tǒng)的工作原理是在文件系統(tǒng)上的簡(jiǎn)單地版本化文件。 例如典型的應(yīng)用程序文件,如HTML頁(yè)面,圖片,CSS,項(xiàng)目配置文件和其他位于文件系統(tǒng)中的分散成小單元的文件。 問(wèn)題是,這不是關(guān)系型數(shù)據(jù)庫(kù)的工作方式。 相反,你面對(duì)的是這些大的數(shù)據(jù)文件和日志文件,其中包括一大堆不同的對(duì)象和數(shù)據(jù)。 當(dāng)涉及到版本操縱 是相當(dāng)混亂的。
數(shù)據(jù)庫(kù)版本有一些可用的工具,如來(lái)自Red Gate的非常優(yōu)秀的SQL源代碼操縱 工具。 去年我寫(xiě)了這個(gè)詳細(xì)的文章——用Red Gate起舞你的SQL源代碼操縱 世界,所以我不會(huì)再深入的細(xì)節(jié),我只想說(shuō),現(xiàn)在數(shù)據(jù)庫(kù)版本操縱 很容易!
說(shuō)實(shí)話,如果現(xiàn)在你沒(méi)有版本操縱 那么在開(kāi)發(fā)中你的數(shù)據(jù)庫(kù)你正背著一個(gè)很大的風(fēng)險(xiǎn)。 進(jìn)行更改時(shí),沒(méi)有一個(gè)單一的事實(shí)來(lái)源,沒(méi)有回滾位置以及不容易和團(tuán)隊(duì)協(xié)作。
8。 編譯輸出不應(yīng)加入源代碼操縱
注意:構(gòu)建項(xiàng)目自動(dòng)生成的任何結(jié)果不應(yīng)該提交到源代碼操縱 中。 對(duì)于的.NET人們,意味著幾乎所有在“bin”和“obj”的文件夾的文件,這通常會(huì)是的.dll和.pdb文件。
為什么呢? 因?yàn)槿绻氵@樣做,你的同事會(huì)恨你。 這意味著,每一次他們從版本庫(kù)更新了變化,則直接用你的覆蓋了他們自己的編譯輸出。 這將是一個(gè)合并的噩夢(mèng),而且可能打斷下次重新編譯進(jìn)程。 然后一旦他們同樣這樣做重新編譯和重新提交,整個(gè)該死的問(wèn)題以相反的方向被重復(fù),這個(gè)時(shí)候你是在接收端。
當(dāng)然,另一個(gè)問(wèn)題是,它只是浪費(fèi)版本操縱 機(jī)的磁盤(pán),浪費(fèi)了帶寬和額外的延遲,這需要每次到發(fā)送它在網(wǎng)絡(luò)上,并且浪費(fèi)你每次不可幸免的處理沖突的時(shí)間。
于是,我們又回到了“忽略”的模式,前面提到的。 只要是“bin”和“obj”路徑設(shè)置為忽略,一切都變得非常,非常簡(jiǎn)單。
事實(shí)上,我甚至寫(xiě)了pre-commit鉤子在VCS服務(wù)器上執(zhí)行,只要是這樣的內(nèi)容,絕不會(huì)到放進(jìn)源代碼操縱 。
9。 沒(méi)有人在乎你的個(gè)人用戶設(shè)置
說(shuō)實(shí)話,我覺(jué)得很常見(jiàn)地人們甚至不知道他們提交了自己的個(gè)人設(shè)置到源代碼操縱 。 這里的問(wèn)題是,許多工具會(huì)產(chǎn)生用于治理 自己個(gè)人的,局部的配置。 這些只適用你,其他人通常會(huì)有所不同。 如果你把它們放到VCS,突然間,你都覆蓋對(duì)方的個(gè)人設(shè)置。
例如我在用戶文件中啟用方案分析,對(duì)我來(lái)說(shuō)很好,我喜歡它,其他人卻不。通常情況下,因?yàn)樗麄兊玫降氖抢淆g化,極廉價(jià)的PC,但我卻不。 問(wèn)題的關(guān)鍵是,我不應(yīng)該強(qiáng)迫其他人用我的設(shè)置 。
.suo文件同樣,里面沒(méi)有美麗的XML,該文件記錄的東西二進(jìn)制,如解決方案資源治理 器狀態(tài),公布設(shè)置和其他你不想去強(qiáng)迫其他人的東西。
10。 依賴關(guān)系也需要放進(jìn)源碼庫(kù)
當(dāng)一個(gè)應(yīng)用程序需要外部依賴才能成功地構(gòu)建和運(yùn)行, 把他們放到源代碼操縱 里。問(wèn)題是,人們傾向于在自己的小環(huán)境用他們自己的設(shè)置和本地依賴并使得一切工作好,然后提交一切到源代碼操縱 里,甩手并認(rèn)為是很酷。 然而,等到任何沒(méi)有相同本地依賴可用的其他人更新后,一切都災(zāi)難性地失敗了。
我曾參與過(guò)一個(gè)項(xiàng)目工程假設(shè)NUnit在機(jī)器上,但這個(gè)時(shí)候,情況并非如此。 幸運(yùn)的是偉大的NuGet解放我出來(lái),但事情并不總是那么幸運(yùn), 當(dāng)你開(kāi)始發(fā)現(xiàn)缺少依賴時(shí)總是需要一番查找擺弄。 在某些情況下,他們沒(méi)有公開(kāi)可用,要試圖跟蹤這將是是徹頭徹尾的痛苦。
我曾碰到這種情況,我從代碼庫(kù)里檢出一個(gè)項(xiàng)目,去運(yùn)行它,發(fā)現(xiàn)缺少組件位于“C:\ Program Files......”路徑。 我花了幾小時(shí)試圖追查誰(shuí)最后成功運(yùn)行它,然后組裝起來(lái),把它放在項(xiàng)目里一個(gè)“庫(kù)”文件夾中,傳到VCS。
當(dāng)然,如果你工作在任何類型的持續(xù)集成環(huán)境中,你的構(gòu)建服務(wù)器要安裝這些庫(kù)。 道格·拉思伯恩最近他寫(xiě)了有關(guān)源代碼操縱 里的第三方工具 。
那么大家?guī)蛡€(gè)忙,從第1天開(kāi)始確保應(yīng)用程序的構(gòu)建和運(yùn)行所需的一切都在VCS。
總結(jié)
說(shuō)實(shí)話,這些事情都不難,真的都很基本:盡早并頻繁提交,知道你正在提交什么,什么應(yīng)該在VCS里,解釋你的提交,并確保你自己親自提交,不要忘了數(shù)據(jù)庫(kù),別忘記依賴。 但請(qǐng)忘記VSS。