SVN(版本管理)教程
Apache Subversion(简称SVN),一个开放源代码的版本控制系统,相较于RCS、CVS,它采用了分支管理系统,它的设计目标就是取代CVS。互联网上很多版本控制服务已从CVS转移到了Subversion。
Docker
这里使用最新版本的 Docker-ce,至于如何安装请看 Install Docker-Ce and Images。
安装时需要注意一下 Docker-Ce 的系统版本,因为 kali-linux Rolling 是建立在最新版的 Debian 下,所以运行 get-docker.sh
时会报错,提示没有kali-rolling
版本,这时我们就需要对 docker.list
进行一下修改,。
1 | :~$ sed -i 's|kali-rolling|buster|' /etc/apt/sources.list.d/docker.list |
svn-server 镜像
这里我们使用 garethflowers 的 svn-server 镜像。因为它的镜像开源且体积最小。
安装
- 从 hub.Docker.com 进行安装
1
:~$ sudo docker pull garethflowers/svn-server
- 从源码安装
1
2:~$ git clone https://github.com/garethflowers/docker-svn-server.git
:~$ cd docker-svn-server.git && sudo docker build -t garethflowers/svn-server .
打开SVN
打开一个数据存储在 /home/svn
的容器:
1 | :~$ sudo docker run --name my-svn-server --detach --volume /home/svn:/var/opt/svn --publish 3690:3690 garethflowers/svn-server |
--volume
:将镜像里的/var/opt/svn
映射至实体机上的/home/svn
下。--publish
:将 Docker 的 3690 端口映射至实体机的 3690 端口。
创建一个新的库
在 Docker 容器里使用svnadmin
来创建与管理库。
我们在容器 my-svn-server 里新建一个名为 test 的库:
1 | # Method 1 |
配置
启动方式
- 方式一:多库 svnserve 模式(指定到版本库的上级目录),默认启动模式。客户端使用
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:~$ sudo docker exec -it my-svn-server env TERM=xterm sh -l
262982ca78f2:/var/opt/svn$ cd test
262982ca78f2:/var/opt/svn/test$ vi conf/svnserve.conf
[general]
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
262982ca78f2:/var/opt/svn/test$ vi conf/passwd
[users]
admin = password
test1 = test1_password
test2 = test2_password
262982ca78f2:/var/opt/svn/test$ vi conf/authz
[groups]
g_admin = admin,test1
g_dev = test2
[/]
test1 = r
* =
[test:/]
@g_admin = rw
* =
[test_2:/]
@g_admin = rw
* =svn ls svn://192.168.0.1/test 来访问 test 版本库。 - 方式二:单库模式(-r 只为一个库进行服务)客户端直接使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24:~$ sudo docker exec -it my-svn-server env TERM=xterm sh -l
262982ca78f2:/var/opt/svn$ killall /usr/bin/svnserve
262982ca78f2:/var/opt/svn$ /usr/bin/svnserve --daemon --foreground --root /var/opt/svn/test
262982ca78f2:/var/opt/svn$ cd test
262982ca78f2:/var/opt/svn/test$ vi conf/svnserve.conf
[general]
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
262982ca78f2:/var/opt/svn/test$ vi conf/authz
[groups]
g_admin = admin,test1
g_dev = test2
[/]
test1 = r
@g_admin = rw
* =
262982ca78f2:/var/opt/svn/test$ vi conf/passwd
[users]
admin = password
test1 = test1_password
test2 = test2_passwordsvn ls svn://192.168.0.1/ 即可访问 test 版本库。
svnserve.conf
1 | [general] |
- anon-access: 控制非鉴权用户访问版本库的权限,取值范围为
write/read/none
。 即write
为可读可写,read
为只读,none
表示无访问权限。
默认值:read - auth-access: 控制鉴权用户访问版本库的权限。取值范围为
write/read/none/
。 即write
为可读可写,read
为只读,none
表示无访问权限。
默认值:write - password-db:指定用户口令文件名,通过它实现增加或删除 svn 的用户。除非指定绝对路径,否则文件位置为相对 conf 目录的相对路径。
默认值:passwd
例如:/home/svn/passwd - authz-db: 指定权限配置文件名,通过该文件可以实现以路径为基础的访问控制。 除非指定绝对路径,否则文件位置为相对 conf 目录的相对路径。
默认值:authz - realm: 指定版本库的认证域,即在登录时提示的认证域名称。若两个版本库的 认证域相同,建议使用相同的用户名口令数据文件。
默认值:一个UUID(Universal Unique IDentifier,全局唯一标示)。
passwd
1 | [users] |
用户名口令文件由svnserve.conf
的配置项password-db
指定,默认为 conf 目录中的passwd
。该文件仅由一个[users]
配置段组成。
authz
1 | [groups] |
权限配置文件由svnserve.conf
的配置项authz-db
指定,默认为 conf 目录中的authz
。该配置文件由一个[groups]
配置用户组和若干个版本库路径权限段组成。
SVN Client
- 拉取库
1
2
3
4
5
6
7:~$ svn checkout svn://192.168.0.1/test --username=admin --password=123456789
Checked out revision 0.
# 因为远程库为空,所以这里的 revision 值为 0。检出成功后在当前目录下生成 test 副本目录。查看拉取的内容
:~$ ls -lah test
drwxr-xr-x 2 root root 4.0K Feb 9 11:52 .
drwxr-xr-x 6 root root 4.0K Feb 9 11:50 ..
drwxr-xr-x 4 root root 4.0k Feb 9 11:53 .svn/ - 添加新文件
1
2
3:~$ cd test && echo "Test 01" > test.md
:~/test$ svn add ./*
A test.md - 提交库
1
2
3
4
5:~/test$ svn commit -m "add first file"
Adding test.md
Transmitting file data .done
Committing transaction...
Committed revision 1. - 查看文件的更改
1
2
3
4
5
6
7
8
9
10:~/test$ echo "Test 02" >> test.md
:~/test$ svn diff
Index: test.md
===================================================================
--- test.md (revision 1)
+++ test.md (working copy)
@@ -1 +1,2 @@
Test 01
+Test 02
:~/test$
客户配置
配置文件位于~/.subversion
1 | :~$ ls -lah ~/.subversion |
config
此配置文件里有个重要的参数password-stores
,即在本地缓存已经验证的用户名与密码,这样就不用每次提交修改都需要输入用户名与密码了。
但有一个缺点,就是我们的用户密码在服务器端修改后,我们在本地再次提交文件时会报出密码不正确
的错误。所以这时就需要我们去手动删除~/.subversion/auth/
下的缓存,重新进行用户密码登录。
为此,我们也可以将此值设置为空,阻止 subversion 缓存用户登录凭证。
解决冲突
假设 A、B 两个用户都在版本号为 100 的时候,更新了 HelloWorld.html 这个文件,A 用户在修改完成之后提交 HelloWorld.html 到服务器, 提交成功后 HelloWorld.html 文件的版本号已经变成 101 了。B 用户还在版本号为 100 的 HelloWorld.html 文件上作修改, 修改完成之后提交到服务器时,由于不是在当前最新的 101 版本上做的修改,所以导致提交失败。
此时我们需要
1 | :~/test$ svn update |
这边输入mc
,以本地的文件为主。你也可以使用其选项对冲突的文件进行不同的操作。
默认是更新到最新的版本,我们也可以指定更新到哪个版本
此时工作副本是和仓库已经同步,可以安全地提交更改了
1 | :~/test$ svn commit -m "change HelloWorld.html second" |
版本回退
当我们想放弃对文件的修改,可以使用
svn revert
操作将撤销任何文件或目录里的局部更改。
我们对文件 readme 进行修改,查看文件状态。
1 | :~$ svn status |
这时我们发现修改错误,要撤销修改,通过 svn revert 文件 readme 回归到未修改状态。
1 | :~$ svn revert readme |
再查看状态。
1 | :~$ svn status |
进行 revert 操作之后,readme 文件恢复了原始的状态。 revert 操作不单单可以使单个文件恢复原状, 而且可以使整个目录恢复原状。恢复目录用 -R 命令,如下。
1 | svn revert -R trunk |
但是,假如我们想恢复一个已经提交的版本怎么办。
为了消除一个旧版本,我们必须撤销旧版本里的所有更改然后提交一个新版本。这种操作叫做 reverse merge。
首先,找到仓库的当前版本,现在是版本 22,我们要撤销回之前的版本,比如版本 21。
1 | svn merge -r 22:21 readme |
历史信息
- svn log: 用来展示svn 的版本作者、日期、路径等等。
1
2
3
4# 查看版本6至版本8之间的变化
:~$ svn log -r 6:8
# 查看指定文件的历史信息
:~$ svn log HelloWorld.html - svn diff: 用来显示特定修改的行级详细信息。
1
2
3
4# 查看工作区与版本库中的变化
:~$ svn diff
# 查看工作区文件与版本库号为3的变化
:~$ svn diff -r 3 rule.txt - svn cat: 取得在特定版本的某文件显示在当前屏幕。
1
2# 查看过去版本的文件内容
:~$ svn cat -r 版本号 rule.txt - svn list: 显示一个目录或某一版本存在的文件。
1
2
3# 查看远程目录中的文件:
:~$ svn list svn://192.168.0.1/test
test.md
SVN 分支
Branch 选项会给开发者创建出另外一条线路。当有人希望开发进程分开成两条不同的线路时,这个选项会非常有用。
比如项目 demo 下有两个小组,svn 下有一个 trunk 版。
由于客户需求突然变化,导致项目需要做较大改动,此时项目组决定由小组 1 继续完成原来正进行到一半的工作(某个模块),小组 2 进行新需求的开发。
那么此时,我们就可以为小组2建立一个分支,分支其实就是 trunk 版(主干线)的一个copy版,不过分支也是具有版本控制功能的,而且是和主干线相互独立的,当然,到最后我们可以通过(合并)功能,将分支合并到 trunk 上来,从而最后合并为一个项目。
1 | :~$ svn copy src/ branches/my_src |
References:
wikipedia
runoob
docker
Install Docker and Images