基本介绍
主要功能:
- 工程管理(工程创建、编译、测试、发布),其中工程依赖管理功能非常强大,也是我们要使用它的主要目的
版本说明:
- 3.3.+: JDK1.7及以上
- 3.2.+: JDK1.6及以上
POM (Project Object Model)
Maven的运行是基于一个XML格式的POM文件的,下面是一个简单的POM文件的例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zhilehuo</groupId>
<artifactId>zlhcommon</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>user-deploy</id>
<name>Releases</name>
<url>http://bjoffice1/nexus/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>user-deploy</id>
<name>Snapshot</name>
<url>http://bjoffice1/nexus/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
中央库(Central Repository)
每个Maven项目都可以将自己发布到中央库,发布后其它人就可以在自己的项目中依赖你发布的项目。另外可以自己建私服,将项目发布至自己的私服上。私服是合法的,后边会介绍如何设置仓库地址[点我直接跳过去]。
项目坐标(Coordinates)
- groupId: 组织或工程的标识,全局唯一
- artifactId: 项目名字
- version: 版本
- packaging: 打包格式,比如jar/war/…
- classifier: 类型?翻译不准确,比如一个项目打出来多个jar包,分别适配jdk1.5和jdk1.7,就可以定义两个classifier分别叫jdk5和jdk7(比如
net.sf.json
就是这么干的),还有常见的项目发布时,同时发布了source和doc包,也是通过不同的classifier来实现。
项目依赖(Depencencies)
Maven一个非常重要的功能就是定义项目之间的依赖关系,这给我们带来的好处就是,当我们引用一个库时,只需要在POM中配置要引用这个库即可,而不需要再去手动下载这个库依赖的其它库。
定义项目依赖时,需要用到如下参数:
- groupId,artifactId,version: 必填的3项,定位一个依赖
- classifier,type: 不一定每个项目都需要,type相当于前面的packaging
- scope: 定义依赖的有效范围,比如javax-servlet-api只在编译时使用,部署时不需要,那么scope就要设置为compile,以免打war包时将这个包也打进去
发布项目(Deploy)
我们自己的项目可以发布到Maven库中(中央库,或是私服),发布时有两种版本类型:SNAPSHOT
版本和Release
版本,SNAPSHOT
就是开发中的版本,可能会被频繁更新,Release
则是正式发布的版本,且相同版本不允许覆盖。
定义项目发布时,需要在POM中做如下配置:1
2
3
4
5
6
7
8
9
10
11
12<distributionManagement>
<repository>
<id>user-deploy</id>
<name>Releases</name>
<url>http://bjoffice1/nexus/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>user-deploy</id>
<name>Snapshot</name>
<url>http://bjoffice1/nexus/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
解释几个字段:
id
: 引用的用户认证ID,这是在settings.xml文件中配置的,下边详细说明。name
: 名字而已,没啥用url
: 要提交的仓库地址
发布时,如果当前版本号带有-SNAPSHOT
后缀,则自动发布至snapshot仓库,否则就发布至release仓库。
再来看下settings.xml中的认证配置:1
2
3
4
5
6
7<servers>
<server>
<id>user-deploy</id>
<username>deploy</username>
<password>123456</password>
</server>
</servers>
无需太多解释,id
就是前边pom.xml
引用的字段。
Maven的配置文件
Maven常用的配置文件有两个:setting.xml
和pom.xml
setting.xml
有一个全局的配置,和一个可选的用户自己的配置。全局的setting一般在Maven的安装目录中,比如在我的Mac中,他存在于/Users/nianxingyan/work/develop/tools/apache-maven-3.2.5/conf/settings.xml
。该配置文件中要是关于maven的一些全局设定,比如仓库(Repository)的位置,项目部署时使用的认证信息。pom.xml
一般位于每个工程的根目录下,都是关于项目本身的配置,比如坐标、依赖关系等。
设置仓库位置
在setting.xml
文件中,涉及到两个设置,一个是mirror
,用来配置一个仓库镜像地址,一个是profile
,用来配置Release
和SNAPSHOT
版本使用的镜像。
先来看mirror的配置:1
2
3
4
5
6
7
8<mirrors>
<mirror>
<id>nexus</id>
<mirrorOf>*</mirrorOf>
<name>Zhilehuo Inc. Maven Central</name>
<url>http://bjoffice1/nexus/repository/maven-public/</url>
</mirror>
</mirrors>
我来试图解释一下几个字段:
id
: 镜像的标识mirrorOf
: 可以写个特定的名字,用来后面被profile引用,也可以是*
,意思就是全部name
: 没啥用,说明而已url
: 仓库的地址
再来看看prifile的配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<profiles>
<profile>
<id>development</id>
<repositories>
<repository>
<id>central</id>
<url>http://central</url>
<releases><enabled>true</enabled></releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>http://central</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
挑重点解释一下:
repositories
和pluginRepositories
: 分别代表Release
和SNAPSHOT
版本的仓库配置url
: 这里可以写一个实际的仓库地址,也可以引用上边mirror中配置的地址。http://central
就是引用一个叫central
的镜像,这就是上边的mirrorOf
字段,所以这里其实就是命中了*
这个镜像。release.enable
和snapshots.enable
: 配置这个仓库中哪些类型的版本是有效的。snapshots.updatePolicy
:SNAPSHOT
版本的更新频率,always
就是每次编译都检查新版本,此外还有daily
等。SNAPSHOT
的默认频率好像是daily
。Release
默认的更新频率应该是never
,就是一旦依赖关系下载完成后,只要本地有缓存,就不会去仓库中检查更新。
此外,prifile还要配置一个activeProfile:1
2
3<activeProfiles>
<activeProfile>development</activeProfile>
</activeProfiles>
这里的development
就是刚才profile
中的id
字段。
常用maven命令
maven的可执行程序叫mvn
,命令格式为 mvn [options] [<goal(s)>] [<phase(s)>]
。
我用得也不多,就简单说一下我理解到的吧,如果不对请告诉我:
goal
里边包含phase
,可以理解为phase
是goal
的子任务。有些任务执行时会将goal
和phase
直接写成goal:phase
的形式,比如mvn jetty:run
。下边写到的几个命令应该是goal
级别的。
clean
用来清理项目。mvn编译时生成的中间文件会放在target
目录,这个命令其实就是将target
目录清空。
compile
编译项目,这中间就会进行依赖关系的检查和下载。
package
打包项目,这个步骤包含了compile
,并且会将当前项目打包成一个jar
(也有可能是其它格式),放在target
目录中。
deploy
发布项目,根据项目版本号来决定发布至Release
或是SNAPSHOT
仓库。
Nexus介绍
Nexus是一个开源的maven仓库服务,我们可以用它来搭建我们自己的“私服”。我已经在192.168.10.8上将Nexus环境搭建好了,一会可以试一下。
Nexus中可以创建多个仓库,仓库在创建时有3种类型:
proxy
这是一个代理,一般情况下,我们会创建一个仓库来代理Maven的中央仓库,这样我们在公司内部就可以通过Nexus来访问中央仓库了,带来的好处就是,别人在中央仓库下载过的包,下次再下载时就不用再去远程下了,节省了带宽和时间。hosted
本地仓库,相当于是一个完事的仓库,我们自己发布的项目,如果不想发布到Maven中央库,主可以发布到我们自己的hosted
仓库中。group
这是一个仓库集合,当公司内部拥有不只一个仓库时(同时拥有proxy
和hosted
仓库的情况还是很常见的),为了不让客户端将所有仓库都设置一遍,就可以创建一个group
类型的仓库,将其它的仓库都集成进去,这样客户端只需要设置这个group
仓库就可以了。
Nexus安装后,默认创建了4个仓库:
- maven-central: Maven中央库的代理(
proxy
) - maven-release: 用来存放私有
Release
版本的仓库(hosted
) - maven-snapshot: 用来存储私有
SNAPSHOT
版本的仓库(hosted
) - maven-public: 上边3个仓库的集合(
group
)
注意:
maven-release
和maven-snapshot
是为了管理方便,人为分出来的两个库,其实Release
和SNAPSHOT
版本的库是可以同时发布到一个仓库中的。
在我们的Nexus库中,我还创建了一个3rd-party-repo
仓库,用来存放那些公共的、没有被发布至中央库的第3方库(实际上是存在这种库的,虽然目前这个库里还是空的)。同时将3rd-party-repo
也加到了maven-public
集合中。
将第三方库手动发布至Nexus
上边说到,我们自己创建了一个叫3rd-party-repo
的仓库,用来存放第3方库,下面就来说一下具体如何操作。
Step 1
找到要发布的第3方库(应该就是一个Jar包),然后为它创建一个POM文件。文件名随意,因为一会发布时会指定POM文件。另外,其实maven也支持通过命令行直接发布一个Jar包,但那样的话定义依赖关系就是很麻烦,所以在没有依赖的时候,可以考虑不创建POM文件。这里以POM文件示例。
Step 2
编辑POM文件,需要定义的内容主要包括坐标定义
和依赖关系
。比如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.3rd-party</groupId>
<artifactId>3rd-party-lib</artifactId>
<version>1.5.3</version>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>4.1.3</version>
</dependency>
</dependencies>
</project>
Step 3
执行命令:mvn deploy:deploy-file -Dfile=[jarfile] -DpomFile=[pomfile] -Durl=http://bjoffice1/nexus/repository/3rd-party-repo/ -DrepositoryId=user-deploy
上面参数中,url
就是要发布到的仓库地址,repositoryId
就是之前说到的用户认证。
能不能更简单一点?
上面这种方式写在命令行上的参数还是有点多,所以为了简化,我试过在POM文件中像正常项目一样配置一个distributionManagement
来定义url
和repositoryId
,但是失败了,似乎在部署时maven并没有去关心我配的distributionManagement
这部分,依然还是去读了命令行里的参数。
上面提到的也可以不使用POM文件进行发布,即通过命令行指定项目坐标,命令是这样的:mvn deploy:deploy-file -Dfile=[jarfile] -DgroupId=com.3rd-party -DartifactId=3rd-party-lib -Dversion=1.5.3 -DrepositoryId=user-deploy -Durl=http://bjoffice1/nexus/repository/3rd-party-repo/
Nexus管理后台
- 登录地址:http://bjoffice1/nexus/
- 用户名:admin
- 密码:zlh123456
bjoffice1
这是一个配置在公司内网的域名,将被解释至192.168.10.8
,Nexus就装在这台公司内网的机器上。- 因为Nexus被安装在了公司内网,所以南京的同事是访问不了的,如果以后南京的同事有访问需求,我们再想办法解决。
Nexus仓库地址
仓库类型 | 地址 |
---|---|
依赖下载地址 | http://bjoffice1/nexus/repository/maven-public/ |
内部Release版本发布 | http://bjoffice1/nexus/repository/maven-release/ |
内部SNAPSHOT版本发布 | http://bjoffice1/nexus/repository/maven-snapshots/ |
第3方库发布 | http://bjoffice1/nexus/repository/3rd-party-repo/ |
实际项目处理
下面我根据工作中实际遇到的一些项目类型,来讲一下如何将让现有项目支持Maven。
我先来列举一下我们工作中遇到的项目类型:独立项目
(比如ISAS)、公共库
(比如isasclient)、Web项目
(比如peanut_baby)、可独立运行的Jar包
(比如serveralarm.jar)和Android项目
。
注意:公司内部的项目在定义坐标时,groupId
统一为com.zhilehuo
,artifactId
全部由小写字母
和横线
组成,比如isas
、sum-dem
。
独立项目
在Idea中,在工程上添加Framework,选中maven,IDE会自动在工程根目录创建pom.xml,并更新目录结构:
u
IDEA会主动修改源码目录结构:
- 原来的工程默认源码目录是
src
,默认测试代码目录是test
- 新的工程默认源码目录是
src/main/java
,测试代码目录是src/test/java
;同时,新的工程中还多出来了一种资源目录,我现在不太知道这个目录是干嘛的,猜测是不是打包的时候,资源目录里的东西会被打进去?
之前我们的工程一般会配置一个第3方库的引用目录lib
,改为Maven后,这个目录不再需要,可以在工程设置中删除相关配置,同时删除这个目录,以免混淆视听。
虽然开发阶段不再需要lib目录,但是项目部署时是需要将依赖库上传至线上服务器的,所以在部署阶段,可以将项目依赖的库拷贝出来,这可以通过一个Maven插件来自动实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 > <build>
> <plugins>
> <plugin>
> <groupId>org.apache.maven.plugins</groupId>
> <artifactId>maven-dependency-plugin</artifactId>
> <executions>
> <execution>
> <id>copy-dependencies</id>
> <phase>package</phase>
> <goals>
> <goal>copy-dependencies</goal>
> </goals>
> <configuration>
> <outputDirectory>${build.directory}/lib/</outputDirectory>
> <overWriteReleases>false</overWriteReleases>
> <overWriteSnapshots>false</overWriteSnapshots>
> <overWriteIfNewer>true</overWriteIfNewer>
> </configuration>
> </execution>
> </executions>
> </plugin>
> </plugins>
> </build>
>
现在工程已经配置好了,编译、运行、调试和以前没有差别。
导出Jar包
打包时稍有差别,之前是通过在工程配置中增加Artifact配置来实现导出jar包的,现在可以换个方式了(虽然之前的方式也能用,但是既然用了Maven,就可以抛弃之前的方式了)。
在Idea右侧栏上找到Maven工具,点开,在LifeCycle
下会发现里边列出了一系列的指令,其中包括package
:
双击package
,就相当于执行了mvn package
命令,这时Maven就会编译项目,并在target目录中生成Jar包。这个Jar包的名字是由项目坐标决定的。
公共库
公共库项目与独立运行的项目唯一的不同点就是需要发布。另外,公共库编译时尽量使用jdk1.6,因为依赖的工程可能是jdk1.6的。
关于项目发布的配置可以参考项目发布
如何使用SNAPSHOT版本?
: 发布时,如果版本号带有后缀-SNAPSHOT
,则发布至shapshot库。Snapshot一般是开发中的版本,可能会被频繁更新,比如被一个工程依赖时,为了修改后在那个工程中进行测试,就可以发布一个shapshot版本,然后在那个工程中依赖配置为使用shapshot:
1
2
3
4
5
6 > <dependency>
> <groupId>com.zhilehuo</groupId>
> <artifactId>zlhredis</artifactId>
> <version>1.0-SNAPSHOT</version>
> </dependency>
>
Web项目
在独立运行项目的基础上,需要添加一个jetty插件。不过,jetty插件在运行时不认识Maven的依赖关系,所以需要将依赖的库拷贝至WEB-INF/lib目录下。最终配置是这样的:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.21.v20170120</version>
<configuration>
<httpConnector><port>8090</port></httpConnector>
<webAppSourceDirectory>${basedir}/WebContent/</webAppSourceDirectory>
<webApp>
<contextPath>/peanut_baby</contextPath>
</webApp>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/WebContent/WEB-INF/lib/</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
还要增加一个运行配置:之前启动Jetty时,配置的是Jetty运行模式,现在要修改为使用Maven来启动Jetty,如下图:
之后在运行时,选择jetty:run
,再启动运行或是调试就可以了:
注意:使用Maven后,依赖库的管理就都要在Maven的管理下,也就是说,如果要增加一个引用库时,不能直接拷贝至lib目录,而是要在Maven的依赖配置中进行配置,直接拷贝是不好使的。
补充说明:
使用Maven管理Web项目时,为了使用Servlet和JSP,通常要在依赖中添加servlet-api
和jsp-api
,而在项目发布时,我们又不需要将这两个包拷贝至目标目录,所以,在引入这两个包时可以加上Scope为privoded
可独立运行的Jar包
和独立运行工程的区别是:独立运行工程在运行时一般还需要其它库的支持,自己无法运行;而可独立运行的Jar包,不需要其它库支持,自己即可执行,比如 serveralarm.jar。要达到这种效果,就要求在打包时,将所有依赖库一并打出到Jar包中,并修改MANIFAST文件,设置运行时的入口的类。
要完成这个任务,还要用到一个Maven插件:maven-assembly-plugin
先看一个配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>single</goal></goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>com.message.Send</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>${artifactId}-${version}-executable</finalName>
<appendAssemblyId>false</appendAssemblyId>
<attach>false</attach>
</configuration>
</plugin>
</plugins>
</build>
解释一下上边的配置(只解释我可能知道的):
mainClass
:设置运行时的入口类descriptorRef
:定义了打包的方式,除了jar-with-dependencies
这个好像还有source
,bin
啥的,总之这个就是把依赖的Jar包进行合并。finalName
,apendAssemblyId
,attach
:有点复杂,下边单独解释。
关于finalName
,apendAssemblyId
,attach
这三个标签,我来尝试解释一下吧。
首先,如果不加这3个标签,则package
时会打出来两个包,一个是不带要依赖关系的serveralarm-1.0.jar
,和一个带依赖关系的serveralarm-1.0-jar-with-dependencies.jar
,而且在deploy
时,这两个包都将上传至仓库中。如果不是因为第2个包的名字比较奇怪,那这个结果是比较理想的。
但是这个名字我不能忍……所以就发现了finalName
这个标签,它可以给生成的包改名,于是我加了这个标签,可是结果的包名是这样的:serveralarm-1.0-executable-jar-with-dependencies.jar
竟然还是带着后缀,于是下一步,将appendAssemblyId
配置为false
,再package
,OK,这次生成了两个包的名字是完美的,分别是serveralarm-1.0.jar
和serveralarm-1.0-executable.jar
。
可是,当我deploy
的时候,却发现仓库中只有一个版本的jar包,就是serveralarm-1.2.1.jar
,并没有serveralarm-1.2.1-executable.jar
,而且更奇怪的是,仓库中的serveralarm-1.2.1.jar
,并不是我刚打出来的那个,而是serveralarm-1.2.1-executable.jar
(通过文件大小看出来的,也可以下载下来看)!
下面开始排查问题,我发现了在打包过程中有一个警告:1
2
3
4
5[WARNING] Configuration options: 'appendAssemblyId' is set to false, and 'classifier' is missing.
Instead of attaching the assembly file: /Users/nianxingyan/work/develop/svn/server/ServerNotification/SendSDK/target/serveralarm-1.2.1-executable.jar, it will become the file for main project artifact.
NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic!
[WARNING] Replacing pre-existing project main-artifact file: /Users/nianxingyan/work/develop/svn/server/ServerNotification/SendSDK/target/serveralarm-1.2.1.jar
with assembly file: /Users/nianxingyan/work/develop/svn/server/ServerNotification/SendSDK/target/serveralarm-1.2.1-executable.jar
人家说得很明白,用serveralarm-1.2.1-executable.jar
替换了serveralarm-1.2.1.jar
!为什么这样子……
百度了一顿饭的时间,说说我的理解:appendAssemblyId
为true
时,相当于创建了一个名为jar-with-dependencies
的classifier
,而我们将其设置为false
后,就没有这个classifier
了,虽然我们用finalName
修改了文件名,但Maven仍然认为这个包的classifier
没有被设置,所以新生成的两个包的classifier
都是空,但是jar-with-dependences
是后生成的,所以在逻辑上覆盖了之前生成的包,这样虽然我们能看到两个文件,但是Maven只认识后生成的那个包。
如何解决呢?我试了很多办法,没有成功,最后只能设置了attach
参数为false
,意思就是这个包和项目没啥关系,所以项目发布的时候也不会理它。反正这个可执行的Jar包放到依赖库里也没啥用,所以就这样吧~
Android项目(Gradle)
使用Gradle构建的Android项目,只需要修改一个仓库位置即可:1
2
3
4
5
6buildscript {
repositories {
//mavenCentral()
maven{ url 'http://bjoffice1/nexus/repository/maven-public/'}
}
}
dependencies
如果要加我们自己的包的话,也是一样,格式是<groupid>:<artifactid>:<version>
,比如:1
2
3
4
5buildscript {
dependencies {
classpath 'com.zhilehuo:zlhcommon:1.2.+'
}
}
现有项目SVN的处理
最后说一个SVN的处理。因为目录结构发生了改变,所以SVN处理起来要小心一点。处理流程建议是这样的:
- 先
update
工程,保证本地没有修改 - 在Idea中添加Maven Framework
- 将Idea自动转移至新目录的源码(比如
src/main/java
)整体移动回原来的位置(比如src
),包括测试代码 - 在SVN中将新的目录结构进行
add
操作,原来一些没有用的目录(比如lib
)执行remove
- 在SVN中将原来的代码目录整体
move
到新的目录中 - 提交SVN之前,记得将
target
目录设置为ignore
以上步骤能保证转移过去的代码还能看到历史记录。如果不用move
指令,而是在SVN中将转移过去的代码进行add
操作的话,历史记录就全部丢失了。