SVN实战
作者:vwFisher
时间:2019-07-16
可参考文档:https://www.kancloud.cn/i281151/svn/197154
IDEA配置:https://blog.csdn.net/hello__word__/article/details/81773815
Windows-TortoiseSVN 使用教程:https://www.runoob.com/svn/tortoisesvn-intro.html
目录
- 1 SVN简介
-
2 SVN 命令实战
- 2.1 SVN 启动模式
- 2.2 svnadmin create 创建版本库
- 2.3 svn checkout 检出操作
- 2.4 svn export 导出
- 2.5 svn info 查看信息
- 2.6 svn add 添加文件
- 2.7 svn commit 提交
- 2.8 svn update更新文件
- 2.9 svn status 目录文件状态
- 2.10 svn delete 删除文件
- 2.11 svn lock/unlock 加锁/解锁
- 2.12 svn diff 比较差异
- 2.13 svn log 查看提交日志
- 2.14 svn cat 查看过去版本
- 2.15 svn list 查看目录文件
- 2.16 svn mkdir 创建纳入版本控制下的新目录
- 2.17 svn revert 恢复本地修改
- 2.18 svn revert 版本回退
- 2.19 svn resolve/resolved 解决冲突
- 2.20 svn switch 把工作拷贝更新到别的URL
- 2.21 svn copy 新建分支
- 2.22 svn merge 合并分支
- 个性化定制 (只是简单例子)
- 3. 开发实战
1 SVN简介
Subversion(SVN) 是一个开源的版本控制系統, 也就是说 Subversion 管理着随时间改变的数据。 这些数据放置在一个中央资料档案库(repository) 中。 这个档案库很像一个普通的文件服务器, 不过它会记住每一次文件的变动。 这样你就可以把档案恢复到旧的版本, 或是浏览文件的变动历史。
优于CVS之处:
- 原子提交。一次提交不管是单个还是多个文件,都是作为一个整体提交的。在这当中发生的意外例如传输中断,不会引起数据库的不完整和数据损坏。
- 重命名、复制、删除文件等动作都保存在版本历史记录当中。
- 对于二进制文件,使用了节省空间的保存方法。(简单的理解,就是只保存和上一版本不同之处)
- 目录也有版本历史。整个目录树可以被移动或者复制,操作很简单,而且能够保留全部版本记录。
- 分支的开销非常小。
- 优化过的数据库访问,使得一些操作不必访问数据库就可以做到。这样减少了很多不必要的和数据库主机之间的网络流量。
1.1 SVN 的一些概念
- repository(源代码库):源代码统一存放的地方
- checkout(提取):当你手上没有源代码的时候,你需要从repository checkout一份
- commit(提交):当你已经修改了代码,你就需要Commit到repository
- update(更新):当你已经Checkout了一份源代码, Update一下你就可以和Repository上的源代码同步,你手上的代码就会有最新的变更
日常开发过程其实就是这样的(假设你已经Checkout并且已经工作了几天):Update(获得最新的代码) --> 作出自己的修改并调试成功 --> Commit(大家就可以看到你的修改了) 。
如果两个程序员同时修改了同一个文件呢, SVN可以合并这两个程序员的改动,实际上SVN管理源代码是以行为单位的,就是说两个程序员只要不是修改了同一行程序,SVN都会自动合并两种修改。如果是同一行,SVN会提示文件Confict, 冲突,需要手动确认。
1.2 SVN 的主要功能
- 目录版本控制
- CVS 只能跟踪单个文件的历史, 不过 Subversion 实作了一个 "虚拟" 的版本控管文件系统, 能够依时间跟踪整个目录的变动。 目录和文件都能进行版本控制。
- 真实的版本历史
- 自从CVS限制了文件的版本记录,CVS并不支持那些可能发生在文件上,但会影响所在目录内容的操作,如同复制和重命名。除此之外,在CVS里你不能用拥有同样名字但是没有继承老版本历史或者根本没有关系的文件替换一个已经纳入系统的文件。在Subversion中,你可以增加(add)、删除(delete)、复制(copy)和重命名(rename),无论是文件还是目录。所有的新加的文件都从一个新的、干净的版本开始。
- 自动提交
- 一个提交动作,不是全部更新到了档案库中,就是完全不更新。这允许开发人员以逻辑区间建立并提交变动,以防止当部分提交成功时出现的问题。
- 纳入版本控管的元数据
- 每一个文件与目录都附有一組属性关键字并和属性值相关联。你可以创建, 并儲存任何你想要的Key/Value对。 属性是随着时间来作版本控管的,就像文件內容一样。
- 选择不同的网络层
- Subversion 有抽象的档案库存取概念, 可以让人很容易地实作新的网络机制。 Subversion 可以作为一个扩展模块嵌入到Apache HTTP 服务器中。这个为Subversion提供了非常先进的稳定性和协同工作能力,除此之外还提供了许多重要功能: 举例来说, 有身份认证, 授权, 在线压缩, 以及文件库浏览等等。还有一个轻量级的独立Subversion服务器, 使用的是自定义的通信协议, 可以很容易地通过 ssh 以 tunnel 方式使用。
- 一致的数据处理方式
- Subversion 使用二进制差异算法来异表示文件的差异, 它对文字(人类可理解的)与二进制文件(人类无法理解的) 两类的文件都一视同仁。 这两类的文件都同样地以压缩形式储存在档案库中, 而且文件差异是以两个方向在网络上传输的。
- 有效的分支(branch)与标签(tag)
- 在分支与标签上的消耗并不必一定要与项目大小成正比。 Subversion 建立分支与标签的方法, 就只是复制该项目, 使用的方法就类似于硬连接(hard-link)。 所以这些操作只会花费很小, 而且是固定的时间。
8.Hackability - Subversion没有任何的历史包袱; 它主要是一群共用的 C 程序库, 具有定义完善的API。这使得 Subversion 便于维护, 并且可被其它应用程序与程序语言使用。
- 在分支与标签上的消耗并不必一定要与项目大小成正比。 Subversion 建立分支与标签的方法, 就只是复制该项目, 使用的方法就类似于硬连接(hard-link)。 所以这些操作只会花费很小, 而且是固定的时间。
1.3 版本控制系统的生命周期
-
创建版本库 (SVN启动模式 - 单库 svnserve 方式、多库svnserve方式)
版本库相当于一个集中的空间,用于存放开发者所有的工作成果。版本库不仅能存放文件,还包括了每次修改的历史,即每个文件的变动历史。
Create 操作是用来创建一个新的版本库。大多数情况下这个操作只会执行一次。当你创建一个新的版本库的时候,你的版本控制系统会让你提供一些信息来标识版本库,例如创建的位置和版本库的名字。
-
检出
Checkout 操作是用来从版本库创建一个工作副本。工作副本是开发者私人的工作空间,可以进行内容的修改,然后提交到版本库中。
-
更新
update 操作是用来更新版本库的。这个操作将工作副本与版本库进行同步。由于版本库是由整个团队共用的,当其他人提交了他们的改动后,你的工作副本就会过期。
让我们假设 Tom 和 Jerry 是一个项目的两个开发者。他们同时从版本库中检出了最新的版本并开始工作。此时,工作副本是与版本库完全同步的。然后,Jerry 很高效的完成了他的工作并提交了更改到版本库中。此时 Tom 的工作副本就过期了。更新操作将会从版本库中拉取 Jerry 的最新改动并将 Tom 的工作副本进行更新。 -
执行变更
当检出之后,你就可以做很多操作来执行变更。编辑是最常用的操作。你可以编辑已存在的文件来,例如进行文件的添加/删除操作。
你可以添加文件/目录。但是这些添加的文件目录不会立刻成为版本库的一部分,而是被添加进待变更列表中,直到执行了 commit 操作后才会成为版本库的一部分。
同样地你可以删除文件/目录。删除操作立刻将文件从工作副本中删除掉,但该文件的实际删除只是被添加到了待变更列表中,直到执行了 commit 操作后才会真正删除。
Rename 操作可以更改文件/目录的名字。"移动"操作用来将文件/目录从一处移动到版本库中的另一处。 -
复查变化
当你检出工作副本或者更新工作副本后,你的工作副本就跟版本库完全同步了。但是当你对工作副本进行一些修改之后,你的工作副本会比版本库要新。在 commit 操作之前复查下你的修改是一个很好的习惯。
Status 操作列出了工作副本中所进行的变动。正如我们之前提到的,你对工作副本的任何改动都会成为待变更列表的一部分。Status 操作就是用来查看这个待变更列表。
Status 操作只是提供了一个变动列表,但并不提供变动的详细信息。你可以用 diff 操作来查看这些变动的详细信息。 -
修复错误
我们来假设你对工作副本做了许多修改,但是现在你不想要这些修改了,这时候 revert 操作将会帮助你。
Revert 操作重置了对工作副本的修改。它可以重置一个或多个文件/目录。当然它也可以重置整个工作副本。在这种情况下,revert 操作将会销毁待变更列表并将工作副本恢复到原始状态。 -
解决冲突
合并的时候可能会发生冲突。Merge 操作会自动处理可以安全合并的东西。其它的会被当做冲突。例如,"hello.c" 文件在一个分支上被修改,在另一个分支上被删除了。这种情况就需要人为处理。Resolve 操作就是用来帮助用户找出冲突并告诉版本库如何处理这些冲突。
-
提交更改
Commit 操作是用来将更改从工作副本到版本库。这个操作会修改版本库的内容,其它开发者可以通过更新他们的工作副本来查看这些修改。
在提交之前,你必须将文件/目录添加到待变更列表中。列表中记录了将会被提交的改动。当提交的时候,我们通常会提供一个注释来说明为什么会进行这些改动。这个注释也会成为版本库历史记录的一部分。Commit 是一个原子操作,也就是说要么完全提交成功,要么失败回滚。用户不会看到成功提交一半的情况。
2 SVN 命令实战
这里展示 常用的命令,对于命令一些细节。需要结合 帮助 来查看
查看 svn 命令帮助:svn help
具体命令的帮助:svn help [COMMAND]
2.1 SVN 启动模式
首先,在服务端进行SVN版本库的相关配置
手动新建版本库目录
mkdir /home/svndata
利用svn命令创建版本库
svnadmin create /home/svndata/project1
使用命令svnserve启动服务
svnserve -d -r 目录 --listen-port 端口号
-r: 配置方式决定了版本库访问方式。配置方式的不同,SVN启动就有两种不同的访问方式(单库 svnserve 方式、多库svnserve方式)
--listen-port: 指定SVN监听端口,不加此参数,SVN默认监听3690
-r直接指定到版本库(单库 svnserve 方式)
svnserve -d -r /home/svndata/project1
在这种情况下,一个svnserve只能为一个版本库工作。
authz配置文件中对版本库权限的配置应这样写:
[groups]
admin=user1
dev=user2
[/]
@admin=rw
user2=r
此时访问的路径
svn://192.168.0.1/
就访问到 project1 的版本库 (单一版本)
指定到版本库的上级目录(多库svnserve方式)
svnserve -d -r /home/svndata
这种情况,一个svnserve可以为多个版本库工作
authz配置文件中对版本库权限的配置应这样写:
[groups]
/home/svndata
admin=user1
dev=user2
[project1:/]
@admin=rw
user2=r
[project2:/]
@admin=rw
user2=r
如果此时你还用[/],则表示所有库的根目录,同理,[/project1]表示所有库的根目录下的 project1 目录。
此时访问的路径
svn://192.168.0.1/project1
才是访问到 project1 的版本库
2.2 svnadmin create 创建版本库
格式:svnadmin create /home/svndata/project1
此时可以查看下 创建的资源库目录路径
# ll /home/svndata/project1
总用量 24
drwxr-xr-x 2 root root 4096 7月 16 23:06 conf
drwxr-sr-x 6 root root 4096 7月 16 23:06 db
-r--r--r-- 1 root root 2 7月 16 23:06 format
drwxr-xr-x 2 root root 4096 7月 16 23:06 hooks
drwxr-xr-x 2 root root 4096 7月 16 23:06 locks
-rw-r--r-- 1 root root 229 7月 16 23:06 README.txt
进入 /home/svndata/project1/conf 目录 修改默认配置文件配置,包括svnserve.conf、passwd、authz 配置相关用户和权限。
svn服务配置文件svnserve.conf
svn服务配置文件为版本库目录中的文件conf/svnserve.conf。该文件仅由一个[general]配置段组成。
[general]
anon-access = none
auth-access = write
password-db = /home/svndata/conf/passwd
authz-db = /home/svndata/conf/authz
realm = /home/svn
- anon-access: 控制非鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。 即"write"为可读可写,"read"为只读,"none"表示无访问权限。 缺省值:read
- auth-access: 控制鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。 即"write"为可读可写,"read"为只读,"none"表示无访问权限。 缺省值:write
- authz-db: 指定权限配置文件名,通过该文件可以实现以路径为基础的访问控制。 除非指定绝对路径,否则文件位置为相对conf目录的相对路径。 缺省值:authz
- realm: 指定版本库的认证域,即在登录时提示的认证域名称。若两个版本库的 认证域相同,建议使用相同的用户名口令数据文件。 缺省值:一个UUID(Universal Unique IDentifier,全局唯一标示)。
用户名口令文件passwd
用户名口令由 svnserve.conf 的配置项 password-db 指定,缺省为 conf 目录中的 passwd。该文件仅由一个[users]配置段组成。
[users]配置段的配置行格式如下:<用户名> = <口令>
例如:
[users]
admin = admin
thinker = 123456
权限配置文件,由svnserve.conf的配置项authz-db指定,缺省为conf目录中的authz。该配置文件由一个[groups]配置段和若干个版本库路径权限段组成。
[groups]配置段中配置行格式如下:<用户组> = <用户列表>
版本库路径权限段的段名格式如下:[<版本库名>:<路径>]
例如:
[groups]
g_admin = admin,thinker
[project1:/]
@g_admin = rw
* =
[project2:/home/thinker]
thinker= rw
* = r
2.3 svn checkout 检出操作
Checkout 操作是用来从版本库创建一个工作副本。工作副本是开发者私人的工作空间,可以进行内容的修改,然后提交到版本库中。
命令:svn checkout {REMOTE_URL} [本地路径] [--username 用户名] [--password 密码]
- checkout:可以用 co 简写表示
- {REMOTE_URL}:http://路径(目录或文件的全路径) 或 svn://路径(目录或文件的全路径)
- 如果不带 --password 参数传输密码的话,会提示输入密码,建议不要用明文的--password 选项。
例子:
svn checkout svn://120.77.47.95/project1 ./project1 --username svn --password password
svn checkout http://localhost/test/testapp --username svn -password password
2.4 svn export 导出
导出一个干净的不带.svn文件夹的目录树
命令:svn export [-r 版本号] {REMOTE_URL} [本地路径] [--username 用户名] [--password 密码]
- [-r 版本号] 如果没有指定版本,则导出最新版本
- {REMOTE_URL}:http://路径(目录或文件的全路径) 或 svn://路径(目录或文件的全路径) 或 本地检出的(即带有.svn文件夹的)目录全路径
例子:
svn export svn://120.77.47.95/project1 ./project1 --username svn --password password
svn export svn://localhost/test/testapp --username wzhnsc
svn export ./project1 ./project3
2.5 svn info 查看信息
命令:svn info [FILENAME]
# svn info
Path: .
Working Copy Root Path: /svnTest/project1
URL: svn://120.77.47.95/project1
Relative URL: ^/
Repository Root: svn://120.77.47.95/project1
Repository UUID: 6326bcb1-f436-4566-bf8c-79cbd8bbe825
Revision: 18
Node Kind: directory
Schedule: normal
Last Changed Author: root
Last Changed Rev: 18
Last Changed Date: 2019-07-18 23:24:35 +0800 (四, 18 7 2019)
2.6 svn add 添加文件
添加文件后,进行 commit 提交
命令:svn add {FILE} # 添加文件到本地版本库
例子:
svn add 1.txt # 添加test.php
svn add *.php # 添加当前目录下所有的php文件
svn add * # 添加所有文件(已经添加过的 会有 warning 提示)
2.7 svn commit 提交
命令:svn commit -m {MESSAGE} [-N] [--no-unlock] 文件名
- commit:可以简写为 ci
- MESSAGE:提交注释
例子:
svn commit -m “提交当前目录下的全部在版本控制下的文件“ * <- 注意这个*表示全部文件
svn commit -m “提交我的测试用test.php“ test.php
svn commit -m “提交我的测试用test.php“ -N --no-unlock test.php <- 保持锁就用–no-unlock开关
svn ci -m “提交当前目录下的全部在版本控制下的文件“ * <- 注意这个*表示全部文件
svn ci -m “提交我的测试用test.php“ test.php
svn ci -m “提交我的测试用test.php“ -N --no-unlock test.php <- 保持锁就用–no-unlock开关
2.8 svn update更新文件
命令:svn update [-r 修正版本] [文件名]
例子:
svn update <- 后面没有目录,默认将当前目录以及子目录下的所有文件都更新到最新版本
svn update -r 200 test.cpp <- 将版本库中的文件 test.cpp 还原到修正版本(revision)200
svn update test.php <- 更新与版本库同步。
提交的时候提示过期冲突,需要先 update 修改文件,
然后清除svn resolved,最后再提交commit。
2.9 svn status 目录文件状态
命令:svn status
例子:
# svn status
M 1.txt
? 2.txt
A 3.txt
各字符代表含义:
字符 | 状态 | 说明 |
---|---|---|
A | 添加 | 与上一版相比增加的文件 |
C | 冲突 | 该文件冲突 |
D | 删除 | 该文件已从仓库删除,以后SVN不再跟踪版本 |
M | 修改 | 该文件被修改过 |
S | 处于其他分支 | 当前分支的子路径处于其他分支 |
? | 未纳入版本管理 | 通常是新增文件,SVN还没跟踪该文件的版本。可以使用svn add把文件加入SVN,此时再运行svn status时,文件的状态就显示为A |
! | 文件缺失 | SVN找不到该文件。一般出现在没有使用SVN命令删除文件的情况。当需要从仓库删除某文件时,应该使用svn delete,这样文件的状态就变为D,提交以后该文件的版本就不再被跟踪 |
执行提交后,也会对应信息提示(Adding 代表 添加,Sending 代表 更新)。并且修订版本号自动增加了1
Adding 2.txt
Sending 1.txt
Transmitting file data .done
Committing transaction...
Committed revision 3.
2.10 svn delete 删除文件
删除后注意 用 commit 提交
命令:
svn delete REMOTE_URL -m MESSAGE
svn delete 文件名
- delete,可以简写:del, remove, rm
svn delete svn://localhost/testapp/test.php -m “删除测试文件test.php”
推荐如下操作:
svn delete test.php
2.11 svn lock/unlock 加锁/解锁
命令
svn lock -m “加锁备注信息文本“ [--force] 文件名
svn unlock 文件名
例子:
svn lock -m “锁信测试用test.php文件“ test.php
svn unlock test.php
2.12 svn diff 比较差异
命令:svn diff -r [ 修正版本号m [ | 修正版本号n ]] [DIR|FILENAME]
例子:
svn diff # 什么都不加,会坚持本地代码和缓存在本地.svn目录下的信息的不同;信息太多,没啥用处。
svn diff -r 3 # 比较你的本地代码和版本号为3的所有文件的不同。
svn diff -r 3 text.c # 比较你的本地代码和版本号为3的text.c文件的不同。
svn diff -r 5:6 # 比较版本5和版本6之间所有文件的不同。
svn diff -r 5:6 text.c # 比较版本5和版本6之间的text.c文件的变化。
svn diff -c 6 test.c # 比较版本5和版本6之间的text.c文件的变化。
实例:
- 检查本地修改
- 比较工作拷贝与版本库
- 比较版本库与版本库
- 如果用 svn diff,不带任何参数,它将会比较你的工作文件与缓存在 .svn 的"原始"拷贝。
# svn diff
Index: 1.txt
===================================================================
--- 1.txt (revision 7)
+++ 1.txt (working copy)
@@ -1,4 +1,4 @@
-1111
+121111
2222
3333
4444
- 比较指定文件(下面的 1.txt 可以替换成 ./) 工作拷贝和版本库。
# svn diff -r 3 1.txt
Index: 1.txt
===================================================================
--- 1.txt (revision 3)
+++ 1.txt (working copy)
@@ -1,4 +1,4 @@
-1111
+121111
2222
3333
4444
- 比较版本库与版本库
-r(revision) 传递两个通过冒号分开的版本号,这两个版本会进行比较
svn diff -r 1:3 1.txt
Index: 1.txt
===================================================================
--- 1.txt (revision 1)
+++ 1.txt (revision 3)
@@ -1,5 +1,5 @@
-111
-222
-333
-444
-555
+1111
+2222
+3333
+4444
+5555
2.13 svn log 查看提交日志
命令:svn log [DIR|FILANAME] [-r NUM|NUM] [-v] [-l N -v]
- -r NUM|NUM:查看特定版本之间的信息
例子:
svn log # 什么都不加会显示所有版本commit的日志信息:版本、作者、日期、comment。
svn log -r 4:20 # 只看版本4到版本20的日志信息,顺序显示。
svn log -r 20:5 # 显示版本20到4之间的日志信息,逆序显示。
svn log test.c # 查看文件test.c的日志修改信息。
svn log -r 8 -v # 显示版本8的详细修改日志,包括修改的所有文件列表信息。
svn log -r 8 -v -q # 显示版本8的详细提交日志,不包括comment。
svn log -v -r 88:866 # 显示从版本88到版本866之间,当前代码目录下所有变更的详细信息 。
svn log -v dir # 查看目录的日志修改信息,需要加v。
svn log http://foo.com/svn/trunk/code/ # 显示代码目录的日志信息。
实例:
# svn log -r 3:4
------------------------------------------------------------------------
r3 | root | 2019-07-18 00:50:00 +0800 (四, 18 7 2019) | 1 line
update 2.txt
------------------------------------------------------------------------
r4 | root | 2019-07-18 00:51:51 +0800 (四, 18 7 2019) | 1 line
update 3.txt
------------------------------------------------------------------------
- DIR|FILANAME:查看特定文件(1.txt) 或 路径(./) 文件
# svn log 1.txt
------------------------------------------------------------------------
r7 | root | 2019-07-18 10:56:14 +0800 (四, 18 7 2019) | 1 line
update 3.txt
------------------------------------------------------------------------
r2 | root | 2019-07-18 00:35:50 +0800 (四, 18 7 2019) | 1 line
update 1
------------------------------------------------------------------------
- -v:可以查看目录信息
- -l N -v:显示限定N条记录的目录信息
# svn log -l 2 -v
------------------------------------------------------------------------
r7 | root | 2019-07-18 10:56:14 +0800 (四, 18 7 2019) | 1 line
Changed paths:
A /1.txt (from /1.txt:4)
A /2.txt (from /2.txt:4)
A /3.txt (from /3.txt:4)
update 3.txt
------------------------------------------------------------------------
r6 | root | 2019-07-18 10:55:42 +0800 (四, 18 7 2019) | 1 line
Changed paths:
D /1.txt
update 3.txt
------------------------------------------------------------------------
2.14 svn cat 查看过去版本
只是检查一个过去版本,不希望查看他们的区别,可使用svn cat
命令:svn cat -r 版本号 rule.txt
例子
svn cat -r 4 test.c # 查看版本4中的文件test.c的内容,不进行比较。
2.15 svn list 查看目录文件
可以在不下载文件到本地目录的情况下来察看目录中的文件:
命令:svn list {REMOTE_URL}
例子:
svn list http://svn.test.com/svn # 查看目录中的文件。
svn list -v http://svn.test.com/svn # 查看详细的目录的信息(修订人,版本号,文件大小等)。
svn list [-v] # 查看当前当前工作拷贝的版本库URL。
# svn list http://192.168.0.1/runoob01
README
branches/
clients/
tags/
2.16 svn mkdir 创建纳入版本控制下的新目录
命令
svn mkdir 目录名
svn mkdir -m "新增目录备注文本" http://目录全路径
例子:
svn mkdir newdir
svn mkdir -m "Making a new dir." svn://localhost/test/newdir
注意:
-
添加完子目录后,一定要回到根目录更新一下(创建纳入版本控制下的新目录),不然在该目录下提交文件会提示“提交失败”
-
如果手工在checkout出来的目录里创建了一个新文件夹newsubdir,再用svn mkdir newsubdir命令后,SVN会提示:
svn: 尝试用 “svn add”或 “svn add --non-recursive”代替? svn: 无法创建目录“hello”: 文件已经存在
此时,用如下命令解决:svn add --non-recursive newsubdir
在进入这个newsubdir文件夹,用ls -a查看它下面的全部目录与文件,会发现多了:.svn目录
再用 svn mkdir -m "添hello功能模块文件" svn://localhost/test/newdir/newsubdir 命令,SVN提示:
svn: File already exists: filesystem '/data/svnroot/test/db', transaction '4541-1',
path '/newdir/newsubdir '
2.17 SVN 恢复本地修改
放弃对文件修改
命令:svn revert 文件名
或 svn revert -R 目录名
例子:
svn revert foo.c <- 丢弃对一个文件的修改
svn revert --recursive . <-恢复一整个目录的文件,. 为当前目录
2.18 SVN 版本回退
命令:svn merge -r [当前版本]:[要回滚的版本] 目录名
如:现在是版本 22,我们要撤销回之前的版本,比如版本 21。
svn merge -r 22:21 readme
2.19 svn resolve/resolved 解决冲突
命令:
svn resolved [本地目录全路径] # 让工作拷贝知道已经处理了冲突(删除冲突产生的相关文件)
svn resolve --accept [base | working | mine-conflict | theirs-conflict | mine-full | theirs-full] [conflicting file]
参数 | 说明 |
---|---|
base | 将[your_file].merge-left.[version]做为最终结果 |
working | 把[your_file]解决冲突后的结果做为最终结果 |
mine-conflict | 将[your_file].working做为最终结果 |
theirs-conflict | 将[your_file].merge-right.[version]做为最终结果 |
mine-full | 将所有[your_file].working做为最终结果 |
theirs-full | 将所有[your_file].merge-right.[version]做为最终结果 |
例子:
$ svn update
C foo.c
Updated to revision 31.
如果你在更新时得到冲突,你的工作拷贝会产生三个新的文件:
$ ls
foo.c
foo.c.mine
foo.c.r30
foo.c.r31
当你解决了foo.c的冲突,并且准备提交,运行 svn resolved 让你的工作拷贝知道你已经完成了所有事情。
你可以仅仅删除冲突的文件并且提交,但是 svn resolved 除了删除冲突文件,还修正了一些记录在工作拷贝管理区域的记录数据,所以我们推荐你使用这个命令。
2.20 svn switch 把工作拷贝更新到别的URL
命令:svn switch {REMOTE_URL}
例子:
svn switch http://localhost/test/456 . # (原为123的分支)当前所在目录分支到localhost/test/456
2.21 svn copy 新建分支
copy 分支,有两种用法,一种用户创建 标签。一种用于 创建分支,结合 switch 使用。
命令:
svn copy {SRC_LOCAL_PATH} {TARGET_LOCAL_PATH} # 标签用法:创建标签,只是复制文件,到 目标文件
svn copy {SRC_REMOTE_URL} {TARGET_REMOTE_URL} -m {MESSAGE} # 分支用法:创建 分支到同一个仓库中其他 目录路径下,配合 switch 使用(注意要在 SRC_REMOTE_URL 使用 switch)
例子:
// 创建标签 (将主干库 放到 release (提交创建好目录并提交) 完整版本记录)
# svn copy trunk/ release/project-v1.0
A release/project-v1.0
# svn commit -m '创建 project-v1.0 版本'
2.22 svn merge 合并分支
命令:svn merge branchA branchB
作用:把对branchA的修改合并到分支branchB
个性化定制 (只是简单例子)
svn配置文件: ~/.subversion/config
修改~/.subversion/config,找到如下配置行:
# diff-cmd = diff_program (diff, gdiff, etc.)
将上面那个脚本的路径添加进去就行,修改为
diff-cmd = /usr/local/bin/diffwrap.sh #绝对路径
这样svn diff命令就会默认使用vimdiff比较文件。
diffwrap.sh文件
#! /bin/bash
# for svn diff: 修改~/.subversion/config,找到如下配置行:
# diff-cmd = diff_program (diff, gdiff, etc.)
# diff-cmd = ~/bin/diffwrap.sh
# 参数大于5时,去掉前5个参数;参数小于5,失败,什么也不做
shift 5
# 使用vimdiff比较
vimdiff "$@"
3. 开发实战
实际开发一般通用流程是:
-
获取代码(更新代码)
->修改代码
->更新代码,并解决冲突
->提交更新
-
获取代码(更新代码)
->新建分支
->查看分支
->提交分支(解决冲突)
->合并分支
->删除分支
3.1 解决冲突
假设当前版本1,有一个文件1.txt
如下:
line 1
line 2
A用户进行修改并且提交
line 1
line 2
line 3
此时 B 用户,没有进行 update,也进行修改,再提交
line 1
line 2
line 4 modify
提交,提示 commit(提交) 失败,此时执行 update(更新)
# svn commit -m 'commit r3'
Sending 1.txt
Transmitting file data .done
Committing transaction...
svn: E160028: Commit failed (details follow):
svn: E160028: 文件 “/1.txt” 已经过时
------------------------------------
# svn update
Updating '.':
C 1.txt
Updated to revision 2.
Summary of conflicts:
Text conflicts: 1
Merge conflict discovered in file '1.txt'.
Select: (p) Postpone, # 标记冲突,暂不处理
(df) Show diff, # 显示所有冲突
(e) Edit file, # 编辑冲突 (需要对应 编辑器 用此选项才有用)
(m) Merge, # 合并
(mc) mine-conflict, # 冲突以本地文件为准
(tf) theirs-conflict, # 冲突以远程仓库为准
(s) Show all options: # 显示所有选项
- p (postpone) 标记冲突,暂不处理
如果冲突很严重,需要和提交者讨论解决,可以输入p标记,此时输入svn status显示:
svn status
C 1.txt
? 1.txt.mine
? 1.txt.r1
? 1.txt.r2
Summary of conflicts:
Text conflicts: 1
文件 | 说明 |
---|---|
[your_file] | 所有冲突标记在该文件 |
[your_file].working | 当前工作副本 |
[your_file].merge-left.[version] | 产生冲突前基础版本 |
[your_file].merge-right.[version] | 仓库里的最新版本 |
用一下命令解决冲突
命令:svn resolve --accept [base | working | mine-conflict | theirs-conflict | mine-full | theirs-full] [conflicting file]
解决冲突后,文件状态变为M,这时再向仓库提交代码即可。
- df (Show diff) 显示所有冲突
选择 df (显示冲突) (显示3段,上面是 自己的,中间是 当前本地版本库,下面是 远程版本)
--- 1.txt.r2 - THEIRS
+++ 1.txt - MERGED
@@ -1,5 +1,19 @@
+<<<<<<< .mine
+11
+22
+33
+||||||| .r1
+111
+222
+333
+=======
1111
2222
3333
+>>>>>>> .r2
- m (Merge) 合并冲突,会提示如下:
Merging '1.txt'.
Conflicting section found during merge:
(1) their version (at line 4) |(2) your version (at line 4)
------------------------------------------------------------------------------+------------------------------------------------------------------------------
line 4 |line 4 merge
------------------------------------------------------------------------------+------------------------------------------------------------------------------
Select: (1) use their version, # 使用 远端 的版本
(2) use your version, # 使用 你当前 的版本
(12) their version first, then yours, # 远端版本 放前面,你当前版本代码 放后面
(21) your version first, then theirs, # 你当前版本代码 放前面,远端版本 放后面
(e1) edit their version and use the result, # 编辑远端版本,然后使用其结果 (需要对应编辑器支持)
(e2) edit your version and use the result, # 编辑你当前版本,然后使用其结果 (需要对应编辑器支持)
(eb) edit both versions and use the result, # 编辑2个版本,然后使用其结果 (需要对应编辑器支持)
(p) postpone this conflicting section leaving conflict markers, # 推迟这个冲突的部分留下冲突标记
(a) abort file merge and return to main menu: # 中止文件合并并返回主菜单
由于没有对应编辑器支持,直接编辑,最后都会走到 p,推迟冲突,通过编辑文件 or resolve命令来解决
查看当前文件
- <<<< .mine 到 ||||| .r2 就是你当前版本的代码
- ======= 到 >>>>>>> .r3 就是远端当前版本的代码
line 1
line 2
line 3
<<<<<<< .mine
line 4 merge
||||||| .r2
=======
line 4
>>>>>>> .r3
可以通过resolve 修复,也可以通过 直接修改文件,删除 其他冲突标记文件来解决
3.2 分支开发
// 1. 创建分支 并提交 (此时可以看到 对应目录有该分支,记得 执行下 update 更新当前版本号)
# svn copy svn://120.77.47.95/project1/trunk/ svn://120.77.47.95/project1/branch/dev -m '创建DEV分支'
Committing transaction...
Committed revision 2.
# svn update
// 2. 切换到 DEV 分支进行开发,注意要进入到 trunk 目录进行 switch 操作
# cd trunk
# svn switch svn://120.77.47.95/project1/branch/dev
At revision 22.
// 3. 假设修改文件,更新 到 DEV 分支
# vim 1.txt
# svn commit -m '添加DEV2'
Sending 1.txt
Transmitting file data .done
Committing transaction...
Committed revision 23.
// 4. 切回 主干分支
# svn switch svn://120.77.47.95/project1/trunk/
U 1.txt
Updated to revision 23.
// 5. 合并 DEV 分支文件 到 主干 (如果有冲突,则解决冲突),然后提交
# svn merge svn://120.77.47.95/project1/branch/dev
--- Merging r22 through r23 into '.':
U 1.txt
--- Recording mergeinfo for merge of r22 through r23 into '.':
U .
# svn commit -m '添加DEV2'
Sending .
Sending 1.txt
Transmitting file data .done
Committing transaction...
Committed revision 24.
// 6. 删除 开发的 分支
# svn delete svn://120.77.47.95/project1/branch/dev -m '删除 DEV 分支'
Committing transaction...
Committed revision 25.