概述/背景
項(xiàng)目在開發(fā)過程中的版本盆犁,和在發(fā)布時(shí)的版本應(yīng)該有所區(qū)別戏蔑。發(fā)布的版本應(yīng)該保證一個(gè)版本號(hào)對(duì)應(yīng)唯一的內(nèi)容氧秘。
之前遇到過一個(gè)項(xiàng)目寻行,因?yàn)閜om中的版本號(hào)沒有-SNAPSHOT
点晴,導(dǎo)致兩個(gè)環(huán)境依賴的項(xiàng)目雖然版本號(hào)相同感凤,其實(shí)不是同一個(gè)。當(dāng)時(shí)得出結(jié)論:相同的版本號(hào)只應(yīng)該對(duì)應(yīng)一個(gè)內(nèi)容粒督。
后來系統(tǒng)學(xué)習(xí)了下Maven陪竿,才具體了解到Maven體系中關(guān)于項(xiàng)目版本的標(biāo)準(zhǔn),這里分享出來,希望大家在維護(hù)項(xiàng)目版本的時(shí)候有據(jù)可依族跛。
另外闰挡,Maven中的版本管理需要結(jié)合軟件版本控制工具使用,如Git礁哄、SVN等长酗。雖然目前Git的使用已經(jīng)很普遍了,我的工作環(huán)境使用的是SVN桐绒,就以SVN為例進(jìn)行介紹夺脾。
Maven范圍的版本和SVN范圍的版本有不同的含義。前者面向的是項(xiàng)目茉继,代碼多次修改咧叭,項(xiàng)目的版本號(hào)可以不變;后者面向的是代碼烁竭,每一次修改都是一個(gè)不同的版本菲茬。下文所說的版本一般是指項(xiàng)目的版本,特殊情況下會(huì)說明是代碼版本颖变。
快照版本和發(fā)布版本
快照版本對(duì)應(yīng)開發(fā)過程中的版本生均,特點(diǎn)是快速的迭代更新,同樣的版本號(hào)對(duì)應(yīng)的是項(xiàng)目在一段時(shí)間內(nèi)的開發(fā)過程绿渣。
發(fā)布版本應(yīng)該是一個(gè)穩(wěn)定的版本须尚,它應(yīng)該對(duì)應(yīng)項(xiàng)目在某個(gè)時(shí)刻的狀態(tài) —— 它對(duì)應(yīng)唯一的代碼版本。
快照版本使用-SNAPSHOT
后綴。
在Maven體系中的區(qū)別
Maven解析依賴的一般機(jī)制是:先從本地倉庫找泊脐,找不到再從遠(yuǎn)程倉庫找。換言之顶吮,在本地倉庫找到了父丰,就不會(huì)再去找遠(yuǎn)程倉庫。
如果有2個(gè)項(xiàng)目并行開發(fā)出牧,其中一個(gè)項(xiàng)目B依賴于另一個(gè)項(xiàng)目A穴肘。想象一下A和B都是持續(xù)更新的,項(xiàng)目B的開發(fā)人員如何確保能實(shí)時(shí)獲取項(xiàng)目A的最新內(nèi)容舔痕?
方案一:項(xiàng)目B的開發(fā)人員评抚,每次構(gòu)建之前都手動(dòng)從本地倉庫刪除項(xiàng)目A,這樣構(gòu)建的時(shí)候就會(huì)從遠(yuǎn)程倉庫下載最新的A伯复。
方案二:項(xiàng)目B的開發(fā)人員慨代,遷出項(xiàng)目A的代碼,自己將A項(xiàng)目安裝到本地倉庫啸如。
這兩個(gè)個(gè)方案都不是Maven體系推薦的做法侍匙,方案二讓項(xiàng)目B的開發(fā)人員不得不去搭建項(xiàng)目A的開發(fā)環(huán)境,而且項(xiàng)目A如果出現(xiàn)代碼問題叮雳,項(xiàng)目B的開發(fā)人員可能就無能為力了想暗。方案一增加了需要人工介入的工作量妇汗。
Maven使用SNAPSHOT
來解決這個(gè)問題。如果項(xiàng)目依賴的是一個(gè)SNAPSHOT版本的依賴说莫,Maven會(huì)定期從遠(yuǎn)程倉庫獲取最新的內(nèi)容杨箭,默認(rèn)頻率是一天一次。也可以使用-U參數(shù)來強(qiáng)制更新唬滑。
所以告唆,項(xiàng)目A使用SNAPSHOT版本,項(xiàng)目B就可以定期或者實(shí)時(shí)獲取項(xiàng)目A的最新內(nèi)容晶密。
反之擒悬,如果項(xiàng)目A沒有使用SNAPSHOT
,項(xiàng)目B在第一次從遠(yuǎn)程倉庫下載項(xiàng)目A到本地倉庫之后稻艰,就一直使用本地倉庫的這個(gè)備份懂牧。即使項(xiàng)目A更新了,項(xiàng)目B也不會(huì)知道尊勿,除非人工刪除了項(xiàng)目A在本地倉庫的副本僧凤。
所以,開發(fā)過程中的版本元扔,應(yīng)該使用SNAPSHOT
版本躯保。
發(fā)布版本的版本號(hào)約定
一般的情況下是下面這種結(jié)構(gòu):
<主版本>.<次版本>.<增量版本> 比如 1.1.2
各版本的作用如下:
- 主版本
項(xiàng)目的重大架構(gòu)變更 - 次版本
較大范圍的功能變化 - 增量版本
大量或緊急bug修復(fù)
這只是一個(gè)粗略的劃分,大家可以根據(jù)自己的情況討論每一個(gè)版本的使用場(chǎng)景澎语。
通常主版本途事、次版本都會(huì)有,增量版本視情況而定擅羞。
更進(jìn)一步的情況尸变,可以添加里程碑版本,版本的結(jié)構(gòu)如下:
<主版本>.<次版本>.<增量版本>—<里程碑版本> 如 3.1.2-alpha-1
里程碑版本表示達(dá)成項(xiàng)目的某個(gè)里程碑减俏,但通常不夠穩(wěn)定召烂。大部分的公司應(yīng)該不會(huì)使用里程碑版本,在此略過不表娃承。
版本維護(hù)流程
主干奏夫、標(biāo)簽和分支
- 主干
無需多說 - 標(biāo)簽
標(biāo)記某個(gè)有意義的代碼版本,每一個(gè)發(fā)布版本都應(yīng)該打一個(gè)標(biāo)簽草慧。 - 分支
用于并行開發(fā)桶蛔,通常用于已有版本的bug修復(fù)。
流程demo
- 在主干進(jìn)行1.0.0-SNAPSHOT的開發(fā)漫谷,開發(fā)完成之后提交修改的代碼到主干仔雷。修改版本為1.0.0,再次提交,并添加標(biāo)簽碟婆。
- 隨后將版本改為1.1.0-SNAPSHOT电抚,提交。然后開始新一輪的開發(fā)竖共,完成之后提交代碼蝙叛,修改版本為1.1.0,再次提交并打標(biāo)簽公给。
- 接著將版本號(hào)改為1.2.0-SNAPSHOT借帘,提交,并開始新一輪的開發(fā)淌铐,在開發(fā)過程中1.1.0遇到一個(gè)緊急的bug肺然,新建分支并1.1.1-SNAPSHOT,修改版本號(hào)為1.1.1-SNAPSHOT腿准,提交并開始1.1.1-SNAPSHOT的開發(fā)际起。
- 1.1.1-SNAPSHOT開發(fā)完成,提交代碼吐葱。修改版本號(hào)至1.1.1街望,提交并打上標(biāo)簽。此時(shí)可以及時(shí)把1.1.1發(fā)布出去弟跑。同步分支到主干灾前。
- 隨后,1.2.0-SNAPSHOT開發(fā)完成..
版本號(hào)的修改應(yīng)該作為一次單獨(dú)的提交孟辑。在發(fā)布的時(shí)候豫柬,項(xiàng)目版本號(hào)初始為SNAPSHOT版本,提交完所有的代碼之后扑浸,修改版本號(hào)為發(fā)布版本,再提交燕偶;這次提交只修改版本號(hào)喝噪。
在開始新一輪的開發(fā)過程時(shí),修改版本號(hào)為新的SNAPSHOT指么,然后立即提交而不是修改代碼酝惧,版本號(hào)提交之后再開始開發(fā),這次提交只修改版本號(hào)伯诬。
SVN相關(guān)操作
SVN簡(jiǎn)單介紹
SVN是一個(gè)很簡(jiǎn)單的版本控制工具晚唇,你可以下載VisualSVN Server來搭建自己的SVN服務(wù)器。
SVN的代碼主要是在倉庫里管理的盗似,如上圖demo就是一個(gè)倉庫哩陕。完整的倉庫目錄結(jié)構(gòu)如下:
倉庫目錄(Repositories)
|-- 倉庫1
|-- 項(xiàng)目1
|-- 主干(trunk)
|-- 項(xiàng)目代碼
|-- 標(biāo)簽?zāi)夸洠╰ags)
|-- 標(biāo)簽1
|-- 項(xiàng)目代碼
|-- 分支(branches)
|-- 分支1
|-- 項(xiàng)目代碼
可以看到,SVN的每一個(gè)標(biāo)簽或者分支,都是一份完整的代碼副本悍及。
與倉庫同一個(gè)級(jí)別的是用戶等其他闽瓢,可以控制對(duì)倉庫的讀寫權(quán)限,具體沒有深入研究心赶,大家有需要自己研究下扣讼。
SVN操作
這里介紹上文版本維護(hù)流程中涉及到的操作。這里以命令的方式介紹缨叫,使用客戶端界面的自己找一下操作的位置椭符。
初始化項(xiàng)目
初始化項(xiàng)目首先要在VisulSVN Server的具體倉庫下新建一個(gè)項(xiàng)目結(jié)構(gòu):
倉庫-> 右鍵 -> 新建 –> Project Structure …
之后會(huì)生成一個(gè)標(biāo)準(zhǔn)的項(xiàng)目結(jié)構(gòu),包含了trunk耻姥、branches销钝、tags,沒有代碼咏闪。
獲取trunk的url地址曙搬,通過trunk -> 右鍵 -> Copy URL…
在本地項(xiàng)目所在目錄,輸入以下命令:
svn import -m "initial import" . https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk
添加標(biāo)簽
版本號(hào)修改為發(fā)布版本之后鸽嫂,應(yīng)該立即對(duì)當(dāng)前狀態(tài)添加一個(gè)標(biāo)簽:
svn copy https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/tags/1.0-RELEASE -m "tag 1.0-RELEASE"
創(chuàng)建分支
svn copy https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/tags/1.0-RELEASE https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches/1.0.1-SNAPSHOT -m "create branch 1.0.1-SNAPSHOT"
可以看到纵装,添加標(biāo)簽和創(chuàng)建分支本質(zhì)上都是復(fù)制。
切換分支
svn switch https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches/1.0.1-SNAPSHOT
合并分支
svn merge https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches/1.0.1-SNAPSHOT
合并分支的時(shí)候据某,pom文件中的版本號(hào)會(huì)有沖突橡娄。一般選擇使用當(dāng)前的版本號(hào)。
Maven的release插件
在使用自動(dòng)化的插件之前癣籽,建議先手動(dòng)執(zhí)行上面的流程挽唉,熟悉版本維護(hù)的流程之后,再去使用自動(dòng)化插件筷狼。
配置pom文件
pom文件需要添加scm配置和插件配置瓶籽。scm是Software configuration management的縮寫。
<project>
...
<scm>
<connection>scm:svn:https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk</connection>
<developerConnection>scm:svn:https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk</developerConnection>
<url>https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/trunk</url>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<tagBase>https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/tags</tagBase>
<branchBase>https://PC-LIJINLONG9.hikvision.com:444/svn/demo/demo-version/branches</branchBase>
</configuration>
</plugin>
</plugins>
</build>
</project>
scm中配置了trunk的url埂材,connection和developerConnection的值都以scm開頭塑顺,之后跟著版本控制工具的類型svn。除了svn之外俏险,Maven還支持其他的工具严拒,如git。
插件里配置了標(biāo)簽的url和分支的url竖独,其實(shí)如果項(xiàng)目的結(jié)構(gòu)是標(biāo)準(zhǔn)的裤唠,trunk、tags和branches在同一級(jí)莹痢,可以不用配置這兩項(xiàng)种蘸。
配置完之后墓赴,就可以通過mvn命令來自動(dòng)發(fā)布、打標(biāo)簽劈彪、創(chuàng)建分支了竣蹦。
自動(dòng)發(fā)布
插件把發(fā)布分為2步,第1步執(zhí)行上文中版本維護(hù)流程中介紹的發(fā)布流程沧奴,第2步使用mvn deploy
部署構(gòu)建至倉庫痘括。第1步由插件的prepare
來完成,第2步由插件的perform
目標(biāo)來完成滔吠。
如果prepare
執(zhí)行失敗纲菌,可以通過rollback
目標(biāo)來回滾,但是prepare
生成的標(biāo)簽需要手動(dòng)刪除疮绷。
release:prepare
prepare負(fù)責(zé)預(yù)發(fā)布翰舌,在prepare之前,需要確保所有的修改都已經(jīng)提交了冬骚,而當(dāng)前的pom文件中的版本號(hào)還沒有升級(jí)為發(fā)布版本號(hào)椅贱。
prepare所做的工作有:
- 檢查系統(tǒng)是否有未提交的代碼
- 詢問用戶發(fā)布版本號(hào)、標(biāo)簽和下一個(gè)開發(fā)版本號(hào)只冻,并提供默認(rèn)值庇麦。
What is the release version for "demo-version"? (com.hikvision.demo:demo-version) 1.2: : What is SCM release tag or label for "demo-version"? (com.hikvision.demo:demo-version) demo-version-1.2: : What is the new development version for "demo-version"? (com.hikvision.demo:demo-version) 1.3-SNAPSHOT: :
- 修改pom-根據(jù)用戶的輸入,將快照版本升級(jí)為發(fā)布版本
- 修改pom-根據(jù)用戶的輸入喜德,將scm中的地址改為標(biāo)簽對(duì)應(yīng)的地址
- 執(zhí)行Maven構(gòu)建
- 提交pom變更
- 根據(jù)用戶的輸入山橄,新建標(biāo)簽
- 修改pom-根據(jù)用戶的輸入將version升級(jí)為新的快照版本,將scm信息更新舍悯。
- 提交pom變更航棱。
上述的內(nèi)容,正是我們?cè)谏?jí)項(xiàng)目版本需要做的事情萌衬。
使用命令:mvn release:prepare
饮醇。
release:rollback
回退release:prepare
的所執(zhí)行的操作,并提交秕豫。但是歷史記錄會(huì)保留驳阎,創(chuàng)建的標(biāo)簽頁不會(huì)刪除。
使用命令:mvn release:rollback
馁蒂。
release:perform
執(zhí)行版本發(fā)布。是基于發(fā)布版本標(biāo)簽地址所對(duì)應(yīng)的代碼進(jìn)行mvn deploy的結(jié)果蜘腌。
使用命令:mvn release:perform
沫屡。
release:branch
自動(dòng)創(chuàng)建分支。
使用命令:
mvn release:branch -DbranchName=1.1.1 -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false
參考
- 《Maven實(shí)戰(zhàn)》 - 許曉斌