Maven學習(十八)-- Maven最佳實踐:版本管理

找到了一篇博客,很多啊,是講Maven中的版本管理的,很好,分享一下,


原文作者:juvenshun

原文地址:http://juvenshun.iteye.com/blog/376422

-------------------------------------------------------------------------------------

什麼是版本管理

        首先,這裏說的版本管理(version management)不是指版本控制(version control),但是本文假設你擁有基本的版本控制的知識,瞭解subversion的基本用法。版本

管理中說得版本是指構件(artifact)的版本,而非源碼的版本(如subversion中常見的rXXX,或者git中一次提交都有個sha1的commit號)。

        比如我有一個項目,其artifactId爲myapp,隨着項目的進展,我們會生成這樣一些jar:myapp-1.0-SNAPSHOT.jar,myapp-1.0.jar,myapp-1.1-SNAPSHOT.jar,

myapp-1.0.1.jar等等。你可能會說,這很簡單啊,我在POM中改個version,mvn clean install不就完了?但這只是表面,本文我將講述,snapshot和release版本的區別,如何

自動化版本發佈(如果你的項目有幾十個module,你就會覺得手工改POM來升級版本是很痛苦的事情),結合自動化發佈的過程,這裏還會介紹maven-release-plugin。此

外,一些scm概念也會被涉及到,比如tag和branch。

前提:版本控制

        不管怎樣,我們都需要建立一個項目並提交到SCM中,這裏我以subversion爲例。你得有一個配置好的subversion repository,這裏我建立了一個空的svn倉庫,其地址

爲:https://192.168.1.100:8443/svn/myapp/ 現在,該目錄下只有三個空的典型的子目錄:/trunk/, branches/, tags/。分別用來存放主幹,分支,以及標籤。

接着將項目導入到svn倉庫中,到項目根目錄,運行如下命令:

[java] view plaincopy
  1. svn import -m 'project initialization' https://192.168.1.100:8443/svn/myapp/trunk   

(注意,這麼做你會將目錄下所有文件導入到svn庫中,但是這其中某些目錄和文件是不應該被導入的,如/target目錄,以及eclipse相關的項目文件)

目前,我們將項目的版本設置爲1.0-SNAPSHOT。

爲什麼用SNAPSHOT?

        我先說說如果沒有SNAPSHOT會是什麼樣子。假設你的項目有2個模塊,A,B,其中A依賴B。這三個模塊分別由甲,乙兩個個人負責開發。在開發過程中,因爲A是依賴於B

的,因此乙每次做一個改動都會影響到甲,於是,乙提交了一些更改後,需要讓甲看到。這個時候,怎麼做呢?乙對甲說,“你簽出我的代碼,build一下就OK了”,甲有點不情

願,但還是照做了,簽出代碼,svn clean install,然後,發現build出錯了,有個測試沒有pass。甲鬱悶了,對乙說,“你的代碼根本不能用,我不想build,你build好了給我”,

乙看了看確實自己的代碼build不過,於是回去解決了,然後打了個jar包,扔給甲,甲對了對groupId,artifactId,放到了自己的.m2/repository/目錄下,OK,能用了。

於是乙每次更新都這樣做,打包,複製,然後甲粘貼,使用……漸漸的,大家發現這是個很笨的辦法,這是純手工勞動阿,程序員最BS的就是重複勞動。一天,甲對乙說,“你

知道nexus麼?你把你的jar發佈到nexus上就可以了,我要用就自動去下載,這多棒!”乙說“哦?有這好東西,我去看看”於是乙發現了nexus這塊新大陸,併成功的發佈了B到

nexus上。(見,Nexus入門指南,(圖文))。

        但是,請注意,我們這裏的一切都假設沒有SNAPSHOT,因此如果乙不更改版本,甲下載一次如B-1.0.jar之後,maven認爲它已經有了正確的B的版本,就不會再重新下

載。甲發現了這個問題,對乙說“你的更新我看不到,你更新了麼?”乙說“不可能!我看看”,於是檢查一下甲下載的C-1.0.jar,發現那是幾天前的。乙一拍腦袋,說“這簡單,我

更新一下我的版本就好了,我發佈個B-1.1.jar上去,你更新下依賴版本”,甲照做了,似乎這麼做是可行的。

        這裏有一個問題,一次提交就更新一個版本,這明顯不是正確的管理辦法,此外,乙得不停的通知甲更新對B的依賴版本,累不累阿?1.0,或者說1.1,2.0,都代表了穩

定,這樣隨隨便便的改版本,能穩定麼?

        所以Maven有SNAPSHOT版本的概念,它與release版本對應,後者是指1.0,1.1,2.0這樣穩定的發佈版本。

現在乙可以將B的版本設置成1.0-SNAPSHOT,每次更改後,都mvn deploy到nexus中,每次deploy,maven都會將SNAPSHOT改成一個當前時間的timestamp,比如B-1.0-

SNAPSHOT.jar到nexus中後,會成爲這個樣子:B-1.0-20081017-020325-13.jar。Maven在處理A中對於B的SNAPSHOT依賴時,會根據這樣的timestamp下載最新的jar,默

認Maven每天更新一次,如果你想讓Maven強制更新,可以使用-U參數,如:

[java] view plaincopy
  1. mvn clean install -U  

現在事情簡化成了這個樣子:乙做更改,然後mvn deploy,甲用最簡單的maven命令就能得到最新的B。

從1.0-SNAPSHOT到1.0到1.1-SNAPSHOT

SNAPSHOT是快照的意思,項目到一個階段後,就需要發佈一個正式的版本(release版本)。一次正式的發佈需要這樣一些工作:

  1. 在trunk中,更新pom版本從1.0-SNAPSHOT到1.0
  2. 對1.0打一個svn tag
  3. 針對tag進行mvn deploy,發佈正式版本
  4. 更新trunk從1.0到1.1-SNAPSHOT

你可以手工一步步的做這些事情,無非就是一些svn操作,一些pom編輯,還有一些mvn操作。但是你應該明白,手工做這些事情,一來繁瑣,而來容易出錯。因此這裏我介紹使用maven插件來自動化這一系列動作。

SCM

首先我們需要在POM中加入scm信息,這樣Maven才能夠替你完成svn操作,這裏我的配置如下:

[java] view plaincopy
  1. <scm>    
  2.   <connection>scm:svn:http://192.168.1.100:8443/svn/myapp/trunk/</connection>    
  3.   <developerConnection>scm:svn:https://192.168.1.100:8443/svn/myapp/trunk/</developerConnection>    
  4. </scm>    

需要注意的是,很多windows使用的tortoiseSVN客戶端,而沒有svn命令行客戶端,這會導致Maven所有svn相關的工作失敗,因此,你首先確保svn --version能夠運行。

分發倉庫

想要讓Maven幫我們自動發佈,首先我們需要配置好分發倉庫。關於這一點,見Maven最佳實踐:Maven倉庫——分發構件至遠程倉庫。

maven-release-plugin

緊接着,我們需要配置maven-release-plugin,這個插件會幫助我們升級pom版本,提交,打tag,然後再升級版本,再提交,等等。基本配置如下:

[java] view plaincopy
  1. <plugin>    
  2.   <groupId>org.apache.maven.plugins</groupId>    
  3.   <artifactId>maven-release-plugin</artifactId>    
  4.   <version>2.0-beta-7</version>    
  5.   <configuration>    
  6.     <tagBase>https://192.168.1.100:8443/svn/myapp/tags/</tagBase>    
  7.   </configuration>    
  8. </plugin>    
GAV我就不多解釋了,這裏我們需要注意的是configuration元素下的tagBase元素,它代表了我們svn中的tag目錄,也就是說,maven-release-plugin幫我們打tag的時候,其基

礎目錄是什麼。這裏,我填寫了svn倉庫中的標準的tags目錄。

提交代碼

接着,確保你的所有代碼都提交了,如果你有未提交代碼,release插件會報錯,既然你要發佈版本了,就表示代碼是穩定的,所以要麼要麼把代碼提交了,要麼把本地的更改

拋棄了。

開始工作

現在,屏住呼吸,執行:

[java] view plaincopy
  1. mvn release:prepare  


執行過程中,你會遇到這樣的提示:

What is the release version for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) 1.0: :

——“你想將1.0-SNAPSHOT發佈爲什麼版本?默認是1.0。”我要的就是1.0,直接回車。

What is SCM release tag or label for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) myapp-1.0: :

——“發佈的tag標籤名稱是什麼?默認爲myapp-1.0。”我還是要默認值,直接回車。

What is the new development version for "Unnamed - org.myorg:myapp:jar:1.0-SNAPSHOT"? (org.myorg:myapp) 1.1-SNAPSHOT: :

——“主幹上新的版本是什麼?默認爲1.1-SNAPSHOT。”哈,release插件會自動幫我更新版本到1.1-SNAPSHOT,很好,直接回車。

然後屏幕刷阿刷,maven在build我們的項目,並進行了一些svn操作,你可以仔細查看下日誌。

那麼結果是什麼呢?你可以瀏覽下svn倉庫:

  • 我們多了一個tag:https://192.168.1.100:8443/svn/myapp/tags/myapp-1.0/,這就是需要發佈的版本1.0。
  • 再看看trunk中的POM,其版本自動升級成了1.1-SNAPSHOT。

這不正是我們想要的麼?等等,好像缺了點什麼,對了,1.0還沒有發佈到倉庫中呢。

再一次屏住呼吸,執行:

[java] view plaincopy
  1. mvn release:perform  

maven-release-plugin會自動幫我們簽出剛纔打的tag,然後打包,分發到遠程Maven倉庫中,至此,整個版本的升級,打標籤,發佈等工作全部完成。我們可以在遠程Maven

倉庫中看到正式發佈的1.0版本。

這可是自動化的 ,正式的 版本發佈!

Maven的版本規則

前面我們提到了SNAPSHOT和Release版本的區別,現在看一下,爲什麼要有1.0,1.1,1.1.1這樣的版本,這裏的規則是什麼。

Maven主要是這樣定義版本規則的:

[java] view plaincopy
  1. <主版本>.<次版本>.<增量版本>  

比如說1.2.3,主版本是1,次版本是2,增量版本是3。

主版本一般來說代表了項目的重大的架構變更,比如說Maven 1和Maven 2,在架構上已經兩樣了,將來的Maven 3和Maven 2也會有很大的變化。次版本一般代表了一些功能的

增加或變化,但沒有架構的變化,比如說Nexus 1.3較之於Nexus 1.2來說,增加了一系列新的或者改進的功能(倉庫鏡像支持,改進的倉庫管理界面等等),但從大的架構上

來說,1.3和1.2沒什麼區別。至於增量版本,一般是一些小的bug fix,不會有重大的功能變化。

一般來說,在我們發佈一次重要的版本之後,隨之會開發新的版本,比如說,myapp-1.1發佈之後,就着手開發myapp-1.2了。由於myapp-1.2有新的主要功能的添加和變化,

在發佈測試前,它會變得不穩定,而myapp-1.1是一個比較穩定的版本,現在的問題是,我們在myapp-1.1中發現了一些bug(當然在1.2中也存在),爲了能夠在段時間內修復

bug並仍然發佈穩定的版本,我們就會用到分支(branch),我們基於1.1開啓一個分支1.1.1,在這個分支中修復bug,並快速發佈。這既保證了版本的穩定,也能夠使bug得到

快速修復,也不同停止1.2的開發。只是,每次修復分支1.1.1中的bug後,需要merge代碼到1.2(主幹)中。

上面講的就是我們爲什麼要用增量版本。

實戰分支

目前我們trunk的版本是1.1-SNAPSHOT,其實按照前面解釋的版本規則,應該是1.1.0-SNAPSHOT。

現在我們想要發佈1.1.0,然後將主幹升級爲1.2.0-SNAPSHOT,同時開啓一個1.1.x的分支,用來修復1.1.0中的bug。

首先,在發佈1.1.0之前,我們創建1.1.x分支,運行如下命令:


[java] view plaincopy
  1. mvn release:branch -DbranchName=1.1.x -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false  

這是maven-release-plugin的branch目標,我們指定branch的名稱爲1.1.x,表示這裏會有版本1.1.1, 1.1.2等等。updateBranchVersions=true的意思是在分支中更新版本,而

updateWorkingCopyVersions=false是指不更改當前工作目錄(這裏是trunk)的版本。

在運行該命令後,我們會遇到這樣的提示:

What is the branch version for "Unnamed - org.myorg:myapp:jar:1.1-SNAPSHOT"? (org.myorg:myapp) 1.1-SNAPSHOT: :

——"分支中的版本號是多少?默認爲1.1-SNAPSHOT" 這時我們想要的版本是1.1.1-SNAPSHOT,因此輸入1.1.1-SNAPSHOT,回車,maven繼續執行直至結束。

接着,我們瀏覽svn倉庫,會看到這樣的目錄:https://192.168.1.100:8443/svn/myapp/branches/1.1.x/,打開其中的POM文件,其版本已經是1.1.1-SNAPSHOT。

分支創建好了,就可以使用release:prepare和release:perform爲1.1.0打標籤,升級trunk至1.2.0-SNAPSHOT,然後分發1.1.0。

至此,一切OK。

小結

本文講述瞭如何使用Maven結合svn進行版本管理。解釋了Maven中SNAPSHOT版本的來由,以及Maven管理版本的規則。並結合SCM的tag和branch概念展示瞭如何使用

maven-release-plugin發佈版本,以及創建分支。本文涉及的內容比較多,且略顯複雜,不過掌握版本管理的技巧對於項目的正規化管理來說十分重要。Maven爲我們提供了一

些一套比較成熟的機制,值得掌握。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章