天天看点

版本控制(一)--svn基本概念、过程

      介绍

         Subversion(SVN)是一个自由开源的版本控制系统,它管理文件和目录可以超越时间,它将一组文件存放在中心版本库,这个版本库很像一个普通的文件服务器,只是它可以记录每一次文件和目录的修改,这便可以使得用户取得之前任意时间点的文件数据版本,从 而可以检查所作的任意修改。从这个意义上讲,许多人将 Subversion 看作一个“时间机器”。

         如果需要搭建一个Subversion版本控制系统的环境,需要在一个支持永久Internet连接 的台式机上部署一个 Subversion Sever 服务端软件。Subversion Sever 服务端软件可以运行 在许多操作系统平台上,比如 Unix,Modern MS Windows 和 Mac OS X 平台上。用户不需要安装 Subversion Sever 服务端软件,他们只需要安装一个 Subversion Client 客户端软件。 这是访问版本控制系统内文件的唯一方法。除了基于命名行的客户端软件之外,现在有许多 更易于人机交互的图形界面(GUIs)客户端工具。另外,在 Internet 上还有非常详尽的关于如何使用 Subversion 的用户手册和文档[。

         大多数使用 MS Windows 的用户安装的客户端软件是 TortoiseSVN,它给用户提供 了最为常用的命令集合,最关键的是它有一套非常友好的用户图形界面;Linux 通常使用命令行来访问版本控制系统 Subversion,或者用户也可以使用eSvn GUI并且搭配 KDiff3 (专门用来比较两个文件之间差异的工具)来使用 SVN。

          先前,在开源软件领域,并行版本系统(CVS)一直是版本控制的选择。CVS 本身是 一个自由软件,CVS 的开发模型成为了开源软件的基石。但是像许多其他开发工具一样, CVS 开始显示出衰老的迹象,Subverrsion 是一个被设计成 CVS 继任的新版本控制系统。 设计者通过两个策略来争取现有的 CVS 用户,一方面,让用户通过 Subversion 构建一个软件开发过程在感觉上和使用 CVS 非常相似;另一方面,Subversion 努力弥补了许多 CVS 暴露出来的明显缺陷,让用户能够更加方便快捷且灵活地控制软件开发过程。

      基本概念

         特性(和CVS比较):

--目录的版本化

--更加好的文件版本管理(例如对文件拷贝,重命名的处理)

--提交的原子性

--元数据的版本化

--可选的网络层

--对文本文件和二进制文件一致的差异比较算法

--高效的分支(branch)和标签(tag)操作

--良好的可维护性

--工作拷贝(work copy):一个 Subversion 的工作拷贝是用户机器的一个本地目录,保存着一 些文件和目录,你可以任意编辑其中的文件,而且如果是源代码文件,你可以像平常一样编辑,你的工作拷贝是你的私有编辑区,在你明确地做了某个特定操作之前。Subversion 不会将你工作拷贝内的任何修改上传 Subversion 服务器与他人所作的修改进行合并。

--基准版本(base):Subversion 会在每个工作拷贝的一个特定位置保存该工作拷贝最后一次提交时的文件及目录情况,这些文件及目录就称为“基准版本”,它可以用来帮 助 Subversion 识别最近哪些文件作了修改,哪一个文件相对于其他人作的修改已 经过期了。

--Head版本:服务器中的最新版本。

--版本库(Repository):按照一定格式存储了所有数据,包括文件和目录,经过授权的客户端可以连接到版本库,读写库中的文件。版本库和普通文件服务器的不同:版本库会记录每一次的更改,所以,客户端可以任意查询更改的历史。例如:ApplicationContext.java的1451版和1450版相比修改了什么?谁作的修改?什么时候作的修改?等等。

--修订版本(Revision):SVN的提交(Commit)操作是把工作拷贝的更改发布到版本库的一个原子操作。每当一次提交完成后,版本库的文件系统就进入了一个新的状态,叫做一次修订(Revision),每一次修订都会赋予一个独一无二的版本号,一般是从0开始的递增自然数,一个比一个大,初始修订版本是0,这只是一个空目录,没有任何内容。随着每次的提交,版本库里仿佛就多了一个当前内容的“快照”。在版本库中,最新的一个修订版本称为HEAD。

      如何实现数据共享:

    解决方案1:锁定-解锁

      问题:       1.可能导致管理问题,如长期锁定文件不放

      2.会导致不必要的顺序开发

      3.可能导致死锁:例如Sally和Harry都需要修改plugin_mgr.c和plugin_mgr.h,两者互相关联,Sally锁定了.c文件而Harry锁定了头文件,就会进入死锁状态。

    解决方案2:Subversion(拷贝-修改-合并模型)

(1).每个工作拷贝会保留一份基准版本。

(2).只要在这个基准版本上有略微的改动,所属的本层文件(夹)及父文件夹就会呈现“叹号” ,也就是说”叹号”出现的充分必要条件是当前工作拷贝与基准版本不同(这个“不同”是非常精确的,包括任何微小的改变)。

(3). 如果 Update 成功,此时基准版本将变成服务器的 Head 版本。 base-->head

(4). 如果 Commit 成功,此时基准版本将变成 Commit 时候的用户工作拷贝。 base-->work copy

(5). 每次 Revert 都是将工作区回复到基准版本(即上次 Update 的或者 Commit 之后的版本)。 work copy-->base

(6). “合并”即所谓的 Merge,很多人不明白这个词的含义,以为是什么神奇的操作,其实这不是事实,一个更好的名称应该是 svn diff-and-apply,即对两个版本库的树进行比较, 然后将区别应用到本地拷贝。此处定义几个名词:比较的左版本树(简称左树)为 “left-tree”,比较的右版本树(简称右树)为“ right-tree”,左右树的差异(通常是右树 相对于左树的差异)为“△修改”,用来接收“ △修改”的目标工作拷贝(简称目标)为 “ des-tree”,那么“合并”的核心概念就是:将差异即 “△修改”应用“des-tree”,因此, Subversion 合并的命令一般含有三个参数 :left-tree,right-tree,des-tree。

7) Subversion 是时间和空间概念的混合体:对于每一个指定的文件夹,通过其日志 log 工具均可以看到该文件(包含子目录)在以前时间里发生的任何一个操作(增,删,改), 并且支持回滚(回滚的参数一般是两个,目录+具体版本);各个目录记录该目录所有子目录(子文件)的历史, 所以越是顶层的目录,就越反映日志的全面性(比如一个子目录被删除了,而用户想回滚找到该目录,那么他应该通过被删除文件的父目录的日志来追回被删除的目录)。             常见操作精确语义: Update语义:          每次 Update 时,服务器的 Head 版本总是要大于等于本地工作区的。要分两种情况讨论:

          A) 工作拷贝与基准版本有差异(工作区文件夹有“叹号”):          下面,请记住一个结论:Update 就是一次典型的“合并”操作! 对于第一种情况,此时又可以细分为两种情况:1) 文本可以合并;2) 二进制文件不能合并。

         下面我们逐个讨论各种情况:                 

          1) 文本文件可以合并:                  此时定义原工作区基准版本为“OldBase”,原工作区修改后版本为“OldRemend”,更新后的 工作区的版本“NewBase”,更新后的工作区修改后文件为 “NewRemend”,此时,

△修改 = OldRemend – OldBase, 叹号的产生即由于这个“△修改”的存在,造成“△修改”的原因有三种-增,删,改。

                 此时 Subversion 在不询问用户的情况下,会自动进行以下操作:OldBase 被 NewBase 覆盖,NewBase 就是服务器的 Head 版本,NewRemend 先被设置成跟 NewBase 一样,然后 接下来 Subversion 将使 NewRemend 反映所有的“△修改”(即将用户原先的本地修改作用 到 NewRemend)。此时又分为两种情况:                   情况一,如果此时的 NewRemend 与“△修改”发生了“冲突”,则会产生冲突告警(现象是生成三个附加文件),用户应当先编辑冲突(决定取舍内容),然后再通过“Resolved”命令来消除告警;或者通过“回滚”Reserved。 最终的效果就是NewRemend在NewBase的基础上舍弃了一部分自己的"△修改"或者舍弃了一部分造成冲突的别人的“△修改”,新的NewRemend是在NewBase的基础上 + 选择的"△修改",NewBase跟Head一致。当commit之后,Head跟NewRemend一致。                   情况二,如果没有发生冲突,则修改后 的 NewRemend 既反映了服务器的最新版本,又能够体现用户在 Update 前的本地修改。

          2) 不可以合并:

                 此时 Subversion 会生成冲突告警(生成两个附加文件),此时应当选择 resolved 来消除告警,然后再删除二进制文件,再 Update;或者 Commite,将“叹号”的文件提交给服务器 作为新的 Head 版本。                   B) 工作拷贝与基准版本没有差异(工作区文件夹“无叹号”):          此时工作拷贝将直接升级至服务器 Head 版本,由于此时“△修改”为空,所以 NewRemend 就是 NewBase,也就是服务器的最新 Head 版本,所以此时可以将 Subversion 的工作理解为:删除了工作区下所有的文件,然后重新下载出一份最新的干净的拷贝。

Commit 精确语义             每次 Commit 的时候(基准版本和工作拷贝肯定不同,因为如果两者相同则不能进行 Commit),Subversion 会检查工作拷贝版本号是否小于服务器 Head 版本号,这将分为两种 情况:

          1) 工作拷贝版本小于 Head 版本:Subversion 会提示用户“这是一个旧的版本”。(因为显然有其他用户做了新的提交使服务器 Head 版本递增了),用户此时正确的操作应该先 Update。             2) 工作拷贝版本等于 Head 版本:此时进行普通的服务器版本提交,将本地最新拷贝同步到服务器 Head 版本。

方案总结:

            拷贝-合并模型假定文件是可以通过上下文合并的。通常情况下, 文本文件(例如源代码以及用纯文本,HTML,TeX等格式保存的文档)因为其内部结构直观可知,容易理解上下文,所以用拷贝—合并方案较好。而 二进制文件(例如用Microsoft Word格式,PDF等格式保存的文档及图片,声音,可执行文件,库等)内部结构复杂,且不容易理解更改处的上下文,采用锁定-解锁方案较好。

ps:svn各状态说明:

         ‘ ‘ no modifications. 没有改动

         ‘A’ Added. 新增加的项目

         ‘C’ Conflicted. 项目内容与更新得到的数据冲突了

         ‘D’ Deleted. 要删除的项目

         ‘I’ Ignored. 已忽略

         ‘M’ Modified. 内容有改动

         ‘R’ Replaced. 在svn仓库中是一个目录, 在本地是一个同名的文件. 反之亦然.

          ‘X’ 项目未版本化, 与外部连接相关

          ‘?’ 未版本化的文件

          ‘!’ 项目丢失, 或者说目录不完整

          ‘~’ 本地有一个未版本化的项目, 在svn仓库里有一个同名项目

     svn仓库不同的访问方式(check out等)

        文件仓库的位置使用 URL 来表示。下表显示了不同的 URL 模式对应的访问方法:

        file://----直接访问本地硬盘上文件仓库;

        http://----通过 WebDAV 协议访问支持 Subversion 的 Apache 2 Web 服务器;

        https://----类似 http://,支持 SSL 加密;

        svn://----通过自带协议访问 svnserve 服务器;

        svn+ssh://----类似 svn://,支持通过 SSH 通道;

------------------------ 可参考: http://svnbook.red-bean.com/en/1.5/svn-book.html

继续阅读