Subversion 实践

Subversion 实践
一个 Subversion 真实使用的例子。

 


Subversion 版本库的 URL
Subversion 使用 URL 来识别 Subversion 版本库中的版本化资源,
通常情况下,这些 URL 使用标准的语法,允许服务器名称和端口作为 URL 的一部分:
$ svn checkout http://svn.example.com:9834/repos

但 是Subversion 处理 URL 的一些细微的不同之处需要注意,例如,使用 file:// 访问方法
的 URL (用来访问本地版本库)必须与习惯一致,可以包括一个 localhost 服务器名或者没有服务
器名:
$ svn checkout file:///var/svn/repos

 

$svn checkout file://localhost/var/svn/repos

同样,在 Windows 平台下使用 file:// 模式时需要使用一个非正式的“标准”语法来访问本机
上不在同一个磁盘分区中的版本库。下面的任意一个 URL 路径语法都可以工作,其中的 X 表示版本库所在的磁盘分区:
C:\> svn checkout file:///X:/var/svn/repos

C:\> svn checkout "file:///X|/var/svn/repos"

在第二个语法里,你需要使用引号包含整个 URL,这样竖线字符才不会被解释为管道。当然,
也要注意 URL 使用普通的斜线而不是 Windows 本地(不是 URL)的反斜线。
也必须意识到 Subversion 的 file:// URL 不能在普通的 web 服务器中工作。

当你尝试在 web 服务器查看一个 file:// URL 时,它会通过直接检测文件系统读取和显示那个位置的文件内容,但是 Subversion 的资源存在于虚拟文件系统

中,你的浏览器不会理解怎样读取这个文件系统。

最后,必须注意 Subversion 的客户端会根据需要自动编码 URL,这一点和一般的 web 浏览器一样,举个例子,如果一个 URL 包含了空格或是一个字符编码大于 128 的 ASCII 字符:
 svn checkout "http://host/path with space/project/españa"

Subversion会封装这些不安全的字符,并且会像你输入了这些字符一样工作:
$ svn checkout http://host/path%20with%20space/project/espa%C3%B1a
如果 URL 包含空格,一定要使用引号,这样你的脚本才会把它做一个单独的 svn 参数。

URL语法:

协议://授权/路径?查询
授权部分一般是服务器的名称或IP地址,有时后面还跟一个冒号和一个端口号。它也可以包含接触服务器必须的用户名称和密码。路径部分包含等级结构的路径定义,一般来说不同部分之间以斜线(/)分隔。询问部分一般用来传送对服务器上的数据库进行动态询问时所需要的参数。完整的、带有授权部分的普通统一资源标志符语法看上去如下:协议://用户名@密码:子域名.域名.顶级域名:端口号/目录/文件名.文件后缀?参数=值#标志

版本库的 URL
Subversion 可以通过多种方式访问—本地磁盘访问,或各种各样不同的网络协议,这要看你的管理员是如何设置。但一个版本库地址永远都只是一个 URL。
模式访问方法
file:/// 直接版本库访问(本地磁盘)
http:// 通过配置Subversion的Apache服务器的WebDAV协议
https:// 与 http:// 类似,但是包括 SSL 加密。
svn:// 通过定制的协议访问 svnserve 服务器
svn+ssh:// 与 svn:// 类似,但通过 SSH 隧道。
关于 Subversion 解析 URL 的更多信息,见第 3.1 节 “Subversion 版本库的 URL”。关于不同的
网络服务器类型,见第 6 章 服务配置。

3.2. 工作副本
你已经阅读过了关于工作副本的内容;现在我们要讲一讲客户端怎样建立和使用它。
一个 Subversion工 作副本是你本地机器上的一个普通目录,保存着一些文件,你可以任意的
编辑文件,而且如果是源代码文件,你可以像平常一样编译,你的工作副本是你的私有工作区,在
你明确的做了特定操作之前,Subversion 不会把你的修改与其他人的合并,也不会把你的修改展示
给别人,你甚至可以拥有同一个项目的多个工作副本。
当你在工作副本作了一些修改并且确认它们工作正常之后,Subversion 提供了一个命令可以
“发布”你的修改给项目中的其他人(通过写到版本库),如果别人发布了各自的修改,Subversion 提
供了手段可以把这些修改与你的工作目录进行合并(通过读取版本库)。
工作副本也包括一些由 Subversion 创建并维护的额外文件,用来协助执行命令。通常情况下,
你的工作副本的每个文件夹都有一个以 .svn 为名的文件夹,也被叫做工作副本的管理目录,这个
目录里的文件能够帮助 Subversion 识别哪些文件做过修改,哪些文件相对于别人的工作已经过期。
一个典型的 Subversion 版本库经常包含许多项目的文件(或者说源代码),通常每一个项目都是
版本库的子目录,在这种布局下,一个用户的工作副本往往对应版本库的的一个子目录。
举一个例子,你的版本库包含两个软件项目,paint 和 calc。每个项目在它们各自的顶级子
目录下,见图 1.6 “版本库的文件系统”。

图 1.6. 版本库的文件系统
为了得到一个工作副本,你必须检出(check out)版本库的一个子树(术语“check out”听起来像是
锁定或者保留资源,实际上不是,只是简单的得到一个项目的私有拷贝),举个例子,检出 /calc
后,你可以得到这样的工作副本:
$ svn checkout http://svn.example.com/repos/calc
A calc/Makefile
A calc/integer.c
A calc/button.c
Checked out revision 56.
$ ls -A calc
Makefile button.c integer.c .svn/
列表中的 A 表示 Subversion 增加了一些条目到工作副本,你现在有了一个 /calc 的个人拷
贝,有一个附加的目录—.svn—保存着前面提及的 Subversion 需要的额外信息。
假定你修改了 button.c,因为 .svn 目录记录着文件的修改日期和原始内容,Subversion 可
以告诉你已经修改了文件,然而,在你明确告诉它之前,Subversion 不会将你的改变公开,将改变
公开的操作被叫做提交(committing,或者是检入)修改到版本库。

将你的修改发布给别人,你可以使用 Subversion 的 commit 命令:
$ svn commit button.c -m "Fixed a typo in button.c."
Sending button.c
Transmitting file data .
Committed revision 57.
这时你对 button.c 的修改已经提交到了版本库,其中包含了关于此次提交的日志信息(例如
是修改了拼写错误)。如果其他人取出了 /calc 的一个工作副本,他们会看到这个文件最新的版
本。
假设你有个合作者 Sally,她和你同时取出了 /calc 的一个工作拷贝,你提交了对 button.c
的修改,Sally 的工作副本并没有改变,Subversion 只在用户要求的时候才改变工作副本。
要使项目最新,Sally 可以通过使用 svn update 命令,要求 Subversion 更新她的工作副本。这
将结合你和所有其他人在她上次更新之后的改变到她的工作副本。
$ pwd
/home/sally/calc
$ ls -A
Makefile button.c integer.c .svn/
$ svn update
U button.c
Updated to revision 57.
svn update 命令的输出表明 Subversion 更新了 button.c 的内容,注意,Sally 不必指定要更
新的文件,subversion 利用 .svn 以及版本库的进一步信息决定哪些文件需要更新。
3.3. 修订版本
svn commit 操作可以作为一个原子事务,发布任意数量文件和目录的修改。在你的工作副本
里,你可以改变文件内容, 删除, 改名,以及复制文件和目录,然后作为一个原子事务提交。
原子事务的意思是:要么所有的改变发生,要么都不发生。Subversion 努力保持原子性,以应
对程序错误, 系统错误, 网络问题和其它用户行为。
每当版本库接受了一个提交,文件系统进入了一个新的状态,叫做一次修订(revision),每一
个修订版本被赋予一个独一无二的自然数,一个比一个大,初始修订号是 0,只创建了一个空目
录,没有任何内容。
图 1.7 “版本库”可以更形象的描述版本库,想象有一组修订号,从 0 开始,从左到右,每一个
修订号有一个目录树挂在它下面,每一个树好像是一次提交后的版本库“快照”。

图 1.7. 版本库
全局版本号
不像其他版本控制系统,Subversion 的修订号是针对整个目录树的,而不是单个文件。每一
个修订号代表了一次提交后版本库整个目录树的特定状态,另一种理解是修订号 N 代表版本
库已经经过了 N 次提交。当 Subversion 用户讨论“ foo.c 的修订号 5” 时,他们的实际意思是
“在修订号 5 时的 foo.c”。需要注意的是,一个文件的修订版本 N 和 M 并不必有所不同。许
多其它版本控制系统使用每文件一个修订号的策略,所以会感觉这些概念有点不一样。(以前
的 CVS 用户可能希望察看附录 B, CVS 用户的 Subversion 指南来得到更多细节。)
需要特别注意的是,工作副本并不一定对应版本库中的单个修订版本,他们可能包含多个修订
版本的文件。举个例子,你从版本库检出一个工作副本,最近的修订号是 4:
calc/Makefile:4
integer.c:4
button.c:4
此刻,工作目录与版本库的修订版本 4 完全对应,然而,你修改了 button.c 并且提交之后,
假设没有别的提交出现,你的提交会在版本库建立修订版本 5,你的工作副本会是这个样子的:
calc/Makefile:4
integer.c:4
button.c:5
假设此刻,Sally 提交了对 integer.c 的修改,建立修订版本 6,如果你使用 svn update 来
更新你的工作副本,你会看到:

calc/Makefile:6
integer.c:6
button.c:6
Sally 对 integer.c 的改变会出现在你的工作副本,你对 button.c 的改变还在,在这个例
子里,Makefile 在 4, 5, 6 的修订版本都是一样的,但是 Subversion 会把他的 Makefile 的修订
号设为 6 来表明它是最新的,所以你在工作副本顶级目录作一次干净的更新,会使得所有内容对应
版本库的同一修订版本。
3.4. 工作副本怎样跟踪版本库
对于工作副本的每一个文件,Subversion在管理区域.svn/记录两项关键的信息:
• 作为工作文件基准的版本(叫做文件的工作版本)
• 本地副本最近一次被版本库更新的时间戳。
给定这些信息,通过与版本库通讯,Subversion可以告诉我们工作文件是处于如下四种状态的
那一种:
未修改且是当前的
文件在工作目录里没有修改,在工作版本之后没有修改提交到版本库。svn commit 操作不做
任何事情,svn update 不做任何事情。
本地已修改且是当前的
在工作目录已经修改,从基本修订版本之后没有修改提交到版本库。本地修改没有提交,因此
svn commit 会成功提交,svn update 不做任何事情。
本地未修改,已过时
这个文件在工作目录没有修改,但在版本库中已经修改了。这个文件最终将更新到最新版本,
成为当时的公共修订版本。svn commit 不做任何事情,svn update 将会取得最新的版本到工
作副本。
本地已修改,已过时
这个文件在工作目录和版本库都得到修改。一个 svn commit 将会失败,这个文件必须首先更
新,svn update 命令会合并公共和本地修改,如果 Subversion 不可以自动完成,将会让用户解
决冲突。
这看起来需要记录很多事情,但是 svn status 命令可以告诉你工作拷贝中文件的状态,关于
此命令更多的信息,请看第 4.3.1 节 “查看你的修改概况”。
3.5. 混合修订版本的工作副本
作为一个普遍原理,Subversion 努力做到尽可能的灵活,一个特殊的灵活特性就是让工作拷贝
包含不同工作修订版本的文件和目录,不幸的是,这个灵活性会让许多新用户感到迷惑。如果上一
个混合修订版本的例子让你感到困惑,这里是一个为何有这种特性和如何利用这个特性的基础介
绍。
12
基本概念
3.5.1. 更新和提交是分开的
Subversion 有一个基本原则就是一个“推”动作不会导致“拉”,反之亦然,因为你准备好了提交你的
修改并不意味着你已经准备好了从其他人那里接受修改。如果你的新的修改还在进行,svnupdate
将会优雅的合并版本库的修改到你的工作副本,而不会强迫将修改发布。
这个规则的主要副作用就是,工作副本需要记录额外的信息来追踪混合修订版本,并且也需要能容
忍这种混合,当目录本身也是版本化的时候情况更加复杂。
举个例子,假定你有一个工作副本,修订版本号是10。你修改了 foo.html,然后执行 svn
commit,在版本库里创建了修订版本15。当成功提交之后,许多用户希望工作副本完全变成修订
版本15,但是事实并非如此。修订版本从10到15会发生任何修改,可是客户端在运行 svn update
之前不知道版本库发生了怎样的改变,svn commit 不会拖出任何新的修改。另一方面,如果 svn
commit 会自动下载最新的修改,可以使得整个工作副本成为修订版本15—但是,那样我们会打破
“推”和“拉”完全分开的原则。因此,Subversion 客户端最安全的方式是标记一个文件— foo.html
—为修订版本15,工作副本余下的部分还是修订版本10。只有运行 svn update 才会下载最新的修
改,整个工作副本被标记为修订版本15。
3.5.2. 混合修订版本很常见
事实上,每次运行 svn commit,你的工作拷贝都会进入混合多个修订版本的状态,刚刚提交的文
件会比其他文件有更高的修订版本号。经过多次提交(其间没有更新),你的工作副本会完全是混合
的修订版本。即使只有你一个人使用版本库,你依然会见到这个现象。为了检查混合工作修订版
本,可以使用 svn status 命令的选项 --verbose (详细信息见第 4.3.1 节 “查看你的修改概况”)。
通常,新用户对于工作副本的混合修订版本一无所知,这会让人糊涂,因为许多客户端命令对于所
检验条目的修订版本很敏感。例如 svn log 命令显示一个文件或目录的历史修改信息(见第 5.1 节
“产生历史修改列表”),当用户对一个工作副本对象调用这个命令,他们希望看到这个对象的整个
历史信息。但是如果这个对象的修订版本已经相当老了(通常因为很长时间没有运行 svnupdate),
此时会显示比这个对象更老的历史。
3.5.3. 混合版本很有用
如果你的项目十分复杂,有时候你会发现强制工作副本的一部分“回溯”到过去非常有用(或者更新
到过去的某个修订版本),你将在第 2 章 基本使用学习到如何这样做。或许你很希望测试某一子目
录下某一子模块的早期版本,又或是要测试一个 bug 什么时候发生,这是版本控制系统像“时间机
器”的一个方面—这个特性允许工作副本的任何一个部分在历史中前进或后退。
3.5.4. 混合版本有限制
无论你如何在工作副本中利用混合修订版本,这种灵活性还是有限制的。
首先,你不可以提交一个不是完全最新的文件或目录,如果有个新的版本存在于版本库,你的删除
操作会被拒绝,这防止你不小心破坏你没有见到的东西。
第二,如果目录已经不是最新的了,你不能提交一个目录的元数据更改。你将会在第 3 章 高级主
题学习附加“属性”,一个目录的工作修订版本定义了许多条目和属性,因而对一个过期的版本提交
属性会破坏一些你没有见到的属性。

4. 总结
我们在这一章里学习了许多 Subversion 的基本概念:
• 我们介绍了中央版本库, 客户工作副本和版本库修订树的概念。
• 我们介绍了两个协作者如何使用 Subversion 通过“拷贝-修改-合并”模型发布和获得对方的修改。
• 我们讨论了一些 Subversion 跟踪和管理工作副本信息的方式。
现在,你一定对 Subversion 在多数情形下的工作方式有了很好的认识,有了这些知识的武装,
你一定已经准备好跳到下一章去了,一个关于 Subversion 命令与特性的详细教程。

 

svnserve - 定制的服务器

轻量级的服务器svnserve,能够给客户在TCP / IP使用一个自定义的,有状态的协议。客户联系一个svnserve服务器通过使用url为开头的
svn:/ /或svn + ssh:/ /方案。本节将解释的不同方式运行svnserve,客户如何验证自己的服务器,以及如何配置适当的访问控制你的存储库。

调用服务器
有许多不同方法运行svnserve:
• 作为一个独立守护进程启动svnserve,监听请求。
• 当特定端口收到一个请求,就会使UNIX的inetd守护进程临时调用svnserve处理。
• 使用SSH在加密通道发起临时svnserve服务。
• 以Windows service服务方式运行svnserve

1.运行svnserve在守护进程模式下

$ svnserve -d
$ # svnserve is now running, listening on port 3690

您可以使用--listen-port 和 --listen-host 选项来定制准确的端口和主机名“绑定”。一旦我们成功地开始svnserve正如前面所解释的那样,它使每个存储库在您的系统上可用网络访问。客户端需要指定一个绝对路径的存储库URL。

例如:
如果一个存储库位于 /var/svn/project1 

 

客户端达到它将通过 $ svn checkout svn://host.example.com/var/svn/project1  

 

提高安全性,你可以通过- r选项svnserve限制其出口只有库低于该路径。

 

例如:
$ svnserve -d -r /var/svn

客户端达到它将通过 $ svn checkout svn://host.example.com/project1

2.通过 inetd 调用 svnserve 

如果你想inetd启动这个过程,你需要通过- i(——inetd)选项,但注意,这还不够

 

$ svnserve -i
( success ( 1 2 ( ANONYMOUS ) ( edit-pipeline ) ) )

 

当使用——inetd选项,Subversion客户通过stdin和stdout使用一个自定义的协议。 这是一个程序通过inetd运行的标准行为。IANA保留Subversion协议端口3690,所以在类unix系统可以添加(如果不存在的话) /etc/services :

svn 3690/tcp # Subversion
svn 3690/udp # Subversion

 

如果系统是使用经典的类Unix的inetd守护进程,你可以在/etc/inetd.conf添加这几行:
svn stream tcp nowait svnowner /usr/bin/svnserve svnserve -i

“svnowner”是一个有适当的权限来访问您的存储库的用户。当一个客户端连接到你的服务器是在端口3690上,inetd 将产生一个svnserve进程来服务与它。当然,您还可能希望添加- r来配置存储库的出口(路径)

3.通过隧道调用 svnserve

 

 

 

 

 

posted @ 2013-05-14 11:18  Neo.  阅读(310)  评论(0编辑  收藏  举报