概述
本文为转载博客,原文地址:http://www.blogjava.net/youxia/archive/2013/12/29/408182.html
参考资料:
1.Maven官方文档http://maven.apache.org/guides/index.html
2.Git官方文档http://git-scm.com/documentation
3.SpringSide4官方文档https://github.com/springside/springside4/wiki
本博文不同于网上随处可见的《Maven使用教程》《Git使用教程》等之类的文章。我并不会从软件的安装和基本的命令开始讲起,而是通过探讨他们包含了哪些设计哲学和能为我们带来什么样的项目管理体验,让大家能在最短的时间内通过一篇博客上手Maven和Git。
Maven是一个优秀的Java项目管理工具。在用Java做项目时,项目的创建、编译、测试、打包和安装部署都需要敲入不少的命令,而且在编译和运行Java程序时,必须能从CLASSPATH中找到该项目依赖的jar包,否则编译无法顺利进行,更不可能成功运行。为解决这些问题,Maven应运而生。
Maven的特点:
1.可以根据模板创建项目,也可以从已有的项目生成模板,这里的模板,Maven术语叫archetype;
2.自动管理依赖的jar;
3.配置文件非常简短;
4.可以有非常丰富的插件,对大部分人来说,使用插件非常简单,不需要了解插件怎么编写,而且插件的下载和管理都是自动的。
Maven关键词:convention; phase; archetype; groupId; artifactId; plugin; task; dependency; repository
以下是我对Maven的理解。
Maven管理一个项目时,会在项目的目录下放一个pom.xml配置文件,该配置文件非常简短。之所以能够做到让配置文件非常简短,是因为Maven管理项目的时候遵循的是一种惯例(convention),Maven项目的目录结构基本是固定的,而且对项目管理中的各个阶段(phase)的定义也是固定的,所以即使不在pom.xml配置文件中做任何特殊定义,也可以使用Maven的标准命令mvn compile、mvn test、mvn package、mvn install自动进行项目的编译、测试、打包、安装。
对于复杂的任务则是通过插件(plugin)来完成,定义在插件中的操作称为任务(task),使用的格式为mvn plugin:task。使用Maven创建一个新项目就是通过archetype插件的generate任务做到的,命令格式为mvn archetype:generate。同样,可以为Maven管理的项目生成Eclipse的项目文件,命令为mvn eclipse:eclipse。插件和依赖项一样,也是自动下载和管理的,不需要用户干预。
自动下载的依赖项和插件都存放在本地仓库(repository)中,该仓库一般位于用户目录的.m2目录下。我们自己的项目执行mvn install时,也默认安装到该仓库中。每一个项目都需要用groupId、artifactId和version来标识,包括我们自己的项目、依赖项、插件、创建新项目要用到的模板等都是如此。使用mvn archetype:generate创建新项目时需要指定archetypeGroupId和archetypeArtifactId。groupId代表该项目所在的小组,比如org.apache.maven,这是Java世界的命名哲学,在这里不详细叙述,artifactId则只需要简单指定一个项目的名字即可,打包成jar文件的时候,会生成名字为artifactId-version.jar的文件。
下面看具体示例。如果要创建一个空项目,使用如下命令:
-DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeArtifactId=maven-archetype-quickstart
-DgroupId=com.xkland.maven-example
-DartifactId=maven-example
-DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeArtifactId=maven-archetype-webapp
-DgroupId=com.xkland.maven-web-example
-DartifactId=maven-web-example
再以SpringSide4为例。先从Github上将SpringSide4克隆下来。(稍后会讲到Git)命令如下:
安装好SpringSide4后,要创建基于SpringSide的项目,先进入support/maven-archetype目录,运行mvn install安装SpringSide的archetype,然后只需要如下命令即可:
-DarchetypeGroupId=org.springside.examples
-DarchetypeArtifactId=quickstart-archetype
-DarchetypeVersion=4.1.1-SNAPSHOT
-DgroupId=com.xkland.springside-sample
-DartifactId=springside-example
软件开发过程中,还有另外一个问题需要解决,那就是源代码的版本控制和多人协作。现在最流行的是版本控制软件是Git,越来越多的开源软件从Subversion迁移到了Git。
Git的特点:
1.Git是分布式的版本控制系统,它没有中心服务器的概念(虽然实际开发中可以建一个中心服务器),每一台开发机器上都保存完整的历史记录;但是它有本地代码仓库和远程代码仓库的概念(不然怎么多人协作?),而且可以追踪多个远程仓库;
2.Git能够非常快地建立分支和合并分支,并具有强大的跟踪分支和切换分支的能力。
以上两个特点决定了使用Git工作的流程。关于Git的使用和工作流程,我将在后面详细叙述。先来看看要理解Git需要理解哪些关键词。
Git的关键词: working directory; repository; stage; commit; remote; branch; merge
下面是我的理解。
每一个项目都应该有一个工作目录(Working directory),我们可以自己建一个目录(这不是废话吗?别急,下面还有。),然后把这个目录里面的代码用Git管理起来(使用git init命令和git add命令,后面详述),也可以通过git clone命令从别的地方克隆一个项目过来自动生成一个工作目录。在工作目录中的文件就是当前编辑和修改的文件,如果是新建立的目录或新clone来的目录,工作目录中的文件就是该项目最新的状态。Git是在本地保存有所有的历史记录和分支记录的,这些内容都在工作目录的.git目录中,称之为本地仓库(local repository)。当切换分支或查看以前的历史版本时,工作目录中的文件自动改变(这才是重点,工作无需切换目录,目录中的文件会自动切换)。工作目录中的文件有三种状态:已修改、已暂存(stage)、已提交。修改后的文件可以先加入暂存区域,一次工作结束后一起提交。
Git是分布式的,没有中心服务器的概念,但实际工作中仍然可以把代码仓库放到一台大家都可以访问的服务器上,做实际的中心服务器使用(仅在小团队时使用此工作流程,原因后面详述)。在本地机器上工作完后,使用git push命令把仓库推送到服务器上,换一个地方换一台机器后,只需要git clone一下,又可以获得所有的代码(包含所有的历史记录及分支)继续工作。服务器故障也没问题,因为每一个工作的机器上都保存有完整的代码仓库,所以从不用担心代码丢失。没有网络也没有关系,在本地机器上照样可以提交(git commit),因为整个仓库就在自己的机器上,当有网络时,push一下就可以了。
Git有远程仓库(remote repository)的概念,而且可以管理很多个远程仓库,远程仓库可以是服务器,也可以是别人的个人计算机(但一般没有人这么用),每一个远程仓库都有一个简短的名字和一个地址,最开始clone代码的那个远程仓库别名往往默认为origin,自己添加的远程仓库可以随意指定别名,当然所有的远程仓库都可以随意修改别名。可以从远程仓库获取代码(git fetch命令或git pull命令),也可以把自己的代码推送到远程仓库(git push命令,需要写权限)。
既然Git即可以随便从远程仓库获取代码,又可以把自己的代码推送到远程仓库,那么当多人协作时,岂不会乱套吗?解决这个问题的,就是Git的必杀之技——创建分支及分支合并。下面要用图表来说明问题了。下面一系列图片来自Git官方网站上的电子书《Pro Git》。
首先,随着一次次的提交,在本地代码库中形成一个主分支,如下图:
有时为了开发新特性,随时可以开一个新分支,如下图:
新分支和主分支之间可以随意切换,随着分支的发展,形式如下图:
主分支也可以向前发展,如下:
最终,当新分支代码很稳定以后,可以将其合并到主分支,如下图:
而能够防止多人协作时出现混乱的关键就在于,当从远程仓库clone代码库到本地或fetch代码库到本地时,远程分支的标记并不等于本地分支的标记。从远程clone一个代码库到本地后,其master分支有两个标记,一个标记为origin/master表示远程库中的master分支,一个标记为master,表示本地的master分支。如下图:
可以想象,由于别人的工作,远程仓库中的master分支肯定会向前继续移动,但是在下次联网之前,该origin/master标记不会移动。而本地的master标记继续向前移动。
直到下次联网,使用git fetch命令将远程仓库的内容取回本地,origin/master标记才会改变位置,这时,看起来就像是两个分支,如下图:
最后,将origin/master分支合并到master分支中(使用get merge命令),本地代码库又一次变成了一个单一的master分支,继续向前开发,并可以将它push到远程仓库,供别人使用。
Git冲突的处理完全靠人工完成。(从逻辑上讲,机器也不可能完美处理冲突。)比如一个小型团队一起工作,他们可以设置一个服务器用于保存远程Git仓库,然后每个人工作之前先从该远程仓库fetch代码,接着工作,工作完成后,先在本地提交,最后push到远程仓库。但是当一个人push的时候,已经有人在他之前push了,如果他们工作在同一个分支,就会出现冲突。解决冲突的办法就是先把别人push的内容再次fetch下来,合并分支,然后再push。
通过之前对git原理的了解,可以分析得出使用Git时有以下几种工作流程:
1.一个人单干,不需要考虑冲突,随时可以开分支、合并分支和切换分支,随时可以本地提交。如果为了防止代码丢失,可以开一个服务器,每次工作完成就push到服务器上;
2.小型团队合作,如前所述,开一个服务器保存代码仓库,然后所有的人把该服务器当成远程仓库,工作之前先fetch,工作之后再push。如果有冲突,则先fetch,合并分支解决冲突后再push。如果团队人数太多,每个人都向该服务器push,那冲突该是有多少?有可能一个开发者第一次向服务器push的时候,有人在他之前已经push过了,他只好先fetch,手工合并解决冲突,可等他再次push的时候,发现又有人再他之前已经push了,于是他只好再做一次解决冲突的流程,可是如果在他工作的时候,又有人push了呢?这也是之前讲的该工作流程只适合小型开发团队的原因。
以上流程经过适当修改也可以供大型团队使用,那就是将团队分组,每个组的成员共用一个服务器当远程仓库,组长合并了该组的工作成果后,再push到另一个服务器当总的远程仓库,这样就可以大大减少冲突的数量,减少工作量。
3.开源项目的合作,在这种情况下,每个人都把自己的仓库暴露在互联网上。开源项目的组织者或负责人将所有人的仓库设为远程仓库,并把有意义的工作合并到主分支,然后发布官方的Git仓库。每个开发者从官方仓库fetch代码后,完成自己的工作,然后再把它push到互联网上自己的仓库,等着项目负责人将自己的工作整合到官方仓库中。如果项目负责人不干了,改人了,只要还有人继续开发,该项目就可以继续下去。碰到团队比较大的情况,也可以进行分组。
服务器的建设也相当简单,因为Git支持以SSH、HTTP等协议传输数据,如果需要对服务器有写权限,就开通SSH服务吧,设一个账户供所有人访问Git仓库即可。如果只需要只读权限,使用任何一个HTTP服务器均可。关于Git服务器的建设,请自行参考官方文档。如果是个人的、开源的项目,可以使用Github网站提供的服务,直接存储在互联网上。(Github私人仓库是要收钱的。)
看来要把Git讲清楚并不容易,用了这么多篇幅。下面把Git常用的命令回顾一下:
git config 配置Git,一般使用不需要特别配置,但至少要设置开发者的名字和邮箱
git init和git add 创建一个新仓库,并跟踪工作目录下的文件
git clone 从远程克隆一个项目,包括工作目录和仓库
git add 将修改后的文件放入缓存区域(staging area),或这表示冲突已经解决
git status 显示文件状态,是已修改还是已缓存还是已提交
git commit 提交项目
git remote 管理远程仓库
git fetch和git pull 从远程仓库抓取数据
git push 向远程仓库推送数据
git branch和git merge 创建分支及合并分支
git checkout 切换分支
git还有一个可视化工具gitk,使用它,可以以图形化的方式查看提交的历史、分支及合并分支等信息。下图是我在springside4目录下执行gitk的截图:
可以看到这里有一段复杂的开分支、合分支的记录。
这篇博文里没有写Maven、Git、Eclipse的安装,因为在我的系统中只需要一个sudo apt-get install maven git eclipse就统统搞定,OpenJDK神马的,作为依赖项当然是自动安装了。对,你没猜错,我用的是Ubuntu。操作系统版本Ubuntu 13.10,maven 3.0.4、git 1.8.3.2、eclipse 3.8。同时给eclipse安装上m2e及EGit插件。
如果只是泛泛地写Maven和Git的用法,那就不是我的风格了,下面当然是show图片了。没有宽屏显示器的朋友们对不起了。不过可以通过Ctrl+鼠标滚轮将网页缩小后查看。
下图,我的Ubuntu桌面:
下图,在虚拟控制台(gnome-terminal)中使用简洁而功能强大的上古神器Vim编辑器,配合半透明背景,酷毙了:
下图,我的工作界面,同时使用控制台和Eclipse,方便高效:
当在Eclipse中选择新建项目的时候,可以选择建立Maven项目或Maven模块,如下图:
点下一步,可以看到让选择archetype,如下图:
再点下一步,发现要填写的内容也不超过之前提到的知识范围:
点Finish,就可以完成一个Maven项目的创建。
当然,也可以导入已有的Maven项目,如下图:
看看pom.xml配置文件的可视化编辑器,这也是我之前不讲pom.xml配置语法的原因,如下图:
要运行Maven项目,请看Run As菜单:
获得一个用Git管理的项目也是有两种途径,一种为使用Eclipse的File->Import菜单,导入一个已经包含Git仓库的项目;另一种方法就是为一个已存在的项目创建一个Git仓库。
用Import导入项目时,也可以从Github克隆。不过我的Egit插件似乎有点问题,使用插件自带的搜索功能不能从Github上找到项目,但是直接指定URL可以。
还是以SpringSide为例。选择File->Import,弹出如下对话框,如下图:
但是在这里只能选择Projects from Git,选择下面的Repositories from GitHub是搜不到项目的。
下一步,如下图:
选择URI,继续下一步,如下图:
输入SpringSide4项目库的地址。看清楚,是https协议哦。继续下一步,如下图:
只有主分支可选,如果不是这样,就选择所有分支。然后下一步,如下图:
在这里需要强调一下,一定要选择第三个:Import as general project。原因就是因为SpringSide的工作目录内没有Eclipse项目所需要的.project文件。如果是用Eclipse创建的项目,本身含有.project文件,就可以使用第一项:Import existing projects。好了,点Finish,springside项目成功导入。所有有关Git的操作都可以在快捷菜单的Team菜单项中找到,如下图:
如果选择Show in history,就可以看到这样的历史记录:
从Github导入项目就展示到这里,其它的功能在IDE环境下大家自己慢慢摸索,应该是很简单的。下面看看为一个已经存在的项目创建Git仓库。
如下图,在maven-example项目的快捷菜单中选择Team->Share project:
弹出如下对话框:
当然是选择Git而不是CVS了。下一步,如下图:
到这里就要注意了,这个对话框中有一个Use or creat repository in parent folder of project的单选框,如果把鼠标放在上面,还有提示。提示说勾选这个单选框是不推荐的,因为会在Eclipse的工作目录中创建Git仓库。而在Eclipse工作目录中创建Git仓库可能会出某些问题。具体是什么问题,EGit User Guide里面有说明。
为了方便起见,还是勾选这个单选框。勾选后,对话框变成下面这样:
点Create Repository后,点Finish就可以完成Git仓库的创建了。
创建Git仓库后,项目中的文件还没有被Git跟踪,所以显示的是问号标记,如下图:
点快捷菜单Team->Add to index后,文件加入追踪,显示的是+号标记,如下图:
提交工作的对话框,如下图:
提交后,项目中的文件标记如下图:
好了,就写这么多吧。截图也是一个很累人的工作。展示这么多图片可不是为了取代官方教程,只是为了展示一下效果。让大家知道这个IDE还是很好很强大的,最重要的是,工作界面是很漂亮的。
重点补充:
Git和Eclipse的EGit插件对于关键词Repository的理解不一致,需要重点强调。在Git中,Repository的定义就是工作目录下的.git目录,工作目录就是是一个Project的根目录。Repository是工作目录的子目录。
为了证明不是我对Repository理解错误,下面是《Pro Git》中的部分原文:
You can get a Git project using two main approaches. The first takes an existing project or directory and imports it into Git. The second clones an existing Git repository from another server.
Initializing a Repository in an Existing Directory
If you’re starting to track an existing project in Git, you need to go to the project’s directory and type
$ git init
This creates a new subdirectory named .git that contains all of your necessary repository files — a Git repository skeleton.
而Eclipse的EGit插件则不一样。在Eclipse的世界里,Project是一个比较小的概念,而且不能嵌套,否则IDE会出问题,再加上Eclipse世界的观点认为我们经常需要在一个workspace中开多个Project。所以Git中的working directory不是一个Project的工作目录,而是一个workspace的工作目录.而Project是workspace的子目录,所以.git目录不应该放到Project的根目录下,而应该放到workspace的根目录下。在workspace目录下放一个.git目录有很多好处,比如可以同时追踪多个项目的源代码,比如可以在删除workspace时同时删除.git目录。但是在Eclipse遍历workspace的时候,.git目录的存在会不会出现问题还说不准。所以最好的办法是把.git目录、Project目录放到workspace之外。如上所述,按Eclipse的哲学,.git目录不应该是Project的子目录,而是Project的平级目录,那么当.git目录和Project目录都放到workspace之外的话,总得有一个目录来存放它们吧,Eclipse就把这个存放它们的那个目录叫Repository。其概念和Git中原有的Repository概念不一样,Eclipse的Repository不是指.git目录,而是Project目录的父目录,在Eclipse中,.git目录叫metadata folder,如果和Git中的Repository是Project的子目录的概念相比较,这两个Repository的概念差了两个辈份。
如下图,将Project纳入Git管理,选择快捷菜单Team->Share Project命令弹出的对话框:
在这个对话框,有一个Use or create repository in parent folder of project的单选框,这里的repository就是指.git目录的祖父目录,所以选中这个单选框,则workspace就相当于是repository,而.git目录就会放到Project目录下。这和我们平时单独使用Git的习惯是一致的,比较容易理解,但是却是Eclipse不推荐的。
按照Eclipse的哲学,我们应该点这个对话框中的Create按钮,这样会弹出如下对话框:
按照我上面这么填写后,相当于创建了一个Repository,其路径为/home/youxia/git/examples,.git目录就会创建在这个目录下,Project目录也会移动到这个目录下,而workspace依然不变。点Finish,会返回上一个对话框,可以看到下面的表格中,显示该项目的current location为/home/youxia/workspace/rcp-example,而创建Repository后,将会将该项目移动到/home/youxia/git/examples/rcp-example,.git目录和rcp-example的项目目录是平级的,都是examples的子目录,examples就是Repository。而且使用这一个.git目录,可以追踪多个项目,也就是说,以后凡是我为了做示范写的代码,不管是swt-example也好,还是springside-example也好,都可以放到examples下,用这一个.git目录保管他们的版本库。
为了证明我没有误解Eclipse的哲学,下面是EGit/User Guide(http://wiki.eclipse.org/EGit/User_Guide)的部分原文:
Git Repositories can be created in different ways, for example by cloning from an existing Repository, by creating one from scratch, or by using the EGit Sharing wizard.
In any case (unless you create a "bare" Repository, but that's not discussed here), the new Repository is essentially a folder on the local hard disk which contains the "working directory" and the metadata folder. The metadata folder is a dedicated child folder named ".git" and often referred to as ".git-folder". It contains the actual repository (i.e. the Commits, the References, the logs and such).
The metadata folder is totally transparent to the Git client, while the working directory is used to expose the currently checked out Repository content as files for tools and editors.
另一段,关于.git目录不应该放到Project目录下,而应该和Project目录平级,并放到workspace之外的:
The reason is that you will never be able to add another project to this Repository, as the .project file will occupy the root folder ; you could still add projects as sub-folders, but this kind of project nesting is known to cause lots of problems all over the place. In order to add another project, you would have to move the project to a sub-folder in the Repository and add the second project as another sub-folder before you could commit this change.
It is a good idea to keep your Repository outside of your Eclipse Workspace
There are several reasons for this: The new Repository will consider the complete folder structure of the Eclipse workspace as (potential) content. This can result in performance issues, for example when calculating the changes before committing (which will scan the complete .metadata folder, for example) ; more often than not, the workspace will contain dead folders (e.g. deleted projects) which semantically are not relevant for EGit but can not be excluded easily.
The metadata (.git-) folder will be a child of the Eclipse Workspace. It is unclear whether this might cause unwanted folder traversals by Eclipse.
You can easily destroy your Repository by destroying your Eclipse Workspace
这里面的细微差别可能会在使用EGit的过程中产生极大困惑。我将其作为重要内容补充道博文末尾,希望能对大家有所帮助。
最后
以上就是复杂香水为你收集整理的浅谈Maven和Git的原理以及在IDE中的使用的全部内容,希望文章能够帮你解决浅谈Maven和Git的原理以及在IDE中的使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复