cvs tutorial
DESCRIPTION
the basic concepts of CVS, the basic usage of CVS client and the pitfall of CVSTRANSCRIPT
本次演示是关于什么的
CVS的简要介绍CVS的基本概念
CVS客户端的基本用法CVS的缺点
CVS的替代者CVS的使用建议
本次演示不是关于什么的
CVS服务器的配置和管理CVS的高级用法
CVS的实现
CVS是什么
CVS是一个集中式的版本控制系统 (VCS)CVS是 Concurrent Versioning System的缩写
CVS由 CVS服务器和 CVS客户端组成第一个版本 1.0于 1999.11发布
最新的稳定版本 1.11.23于 2008.5发布
CVS可以做什么
保存对代码所做的修改查看对代码所做的修改撤销对代码所做的修改为维护旧版本而创建一个维护分支为发布新版本而创建一个发布标签为开发复杂的新功能而创建一个功能分支将维护分支的缺陷修正合并到主干将功能分支中的新功能合并到主干
CVS的基本概念
修订版本 (revision)版本仓库 (repository) 模块 (module)
工作拷贝 (working copy) 主干 (trunk) 分支 (branch) 标签 (tag)
检出 (checkout) 提交 (commit)更新 (update)合并 (merge) 冲突 (conflict)
Copy-Modify-Merge的工作模型
CVS的基本概念
修订版本 (revision)对应了一个文件在某一次提交的修改后的状态。修订版本由一串数字 N.M表示。初始修订版本号为 1.1。比如修订版本为 1.33的 mg.c文件,表示 mg.c文件在经过 33次提交的修改后的状态。
CVS的基本概念
版本仓库 (repository)CVS服务器用于保存一个项目的所有文件的修订版本的地方。对应于 CVS服务器上的一个目录。一个版本仓库下可以有多个项目。每一个项目对应于版本仓库目录的一个子目录。
CVS基本概念只有一个项目的版本仓库:
有多个项目的版本仓库
CVS基本概念
模块 (module)既可以对应于版本仓库本身 (使用 .表示 )、也可以对应版本仓库下的一个文件或者目录,还可以对应于 CVS服务器设置的 CVS模块名。
CVS模块名定义了版本仓库下项目的别名和分组。一个 CVS模块名可以对应一个项目、一个项目的多个文件或者多个项目。通过修改版本仓库中的CVSROOT/modules来定义 CVS模块名。
CVS的基本概念
工作拷贝 (working copy)CVS客户端用于操作版本仓库中的项目的地方。对应于 CVS客户端上的一个目录。对一个版本仓库,每一个开发者都有一个私有的工作拷贝。
CVS的基本概念
检出 (checkout)使用版本仓库创建一个新的工作拷贝
提交 (commit)将工作拷贝中对文件的修改上传到版本仓库
更新 (update)将版本仓库中的文件的修改合并到工作拷贝
CVS的基本概念主干 (trunk)/主分支 (master branch)一个逻辑概念,表示总是用于新版本开发的文件集合。
分支 (branch)一个逻辑概念,表示用于进行已发布版本维护或者新功能开发的文件集合。
标签 (tag)一个逻辑概念,表示构成了版本仓库一个快照的文件集合。
CVS基本概念
合并 (merge)将分支 /主干中的更新应用到主干 /分支的过程。
冲突 (conflict)表示需要合并进来的更新和本地工作拷贝中的更新都修改了某一个文件的同一个地方是由两个开发者都修改了一个文件的同一个地方,并且都尝试提交引起的。需要开发者手动解决。
CVS的基本概念Copy-Modify-Merge的工作模式优点:更好的支持协同开发。过程:对一个版本仓库,每个开发者都有一个对应的工作拷贝。每个开发者都在自己的工作拷贝中对版本仓库的内容进行修改。每一个开发者通过更新、解决冲突、提交等方法将自己的修改合并到版本仓库。
CVS基本概念
Copy-Modify-Merge工作模型
CVS基本概念
Copy-Modify-Merge工作模型
CVS基本概念
Copy-Modify-Merge工作模型
CVS客户端基本操作
以命令行的方式进行演示
CVS命令的基本形式#cvs [cvs-opts] cmd [cmd-opts-and-args]cvs-opts为全局的选项,常用的全局选项包括-Q/-q/-d/-n等。常用的命令包括 login/logout/import/checkout/export/add/diff/commit/log/update/status/remove/tag等。cmd-opts-and-args为命令相关的选项和参数。
CVS客户端基本操作
"登录 "到 CVS服务器的一个版本仓库#cvs -d :pserver:[email protected]:/arago/kernel login
只是进行操作权限的验证和缓存。选项 -d的参数包含了版本仓库的地址和开发者的验证信息 ,称之为版本仓库的 cvs根 (cvs root)。
从 CVS服务器的一个版本仓库 "注销 "#cvs -d :pserver:[email protected]:/arago/kernel logout
CVS客户端基本操作
全局选项 -d的参数 /cvs根 (cvs root)
例如 :pserver:[email protected]:/arago/kernel分为 3部分,使用冒号 (:)分割。分别表示服务器的访问方法: pserver、服务器的地址 arago.com和开发者的访问用户名(bell)和版本仓库的路径 /arago/kernel。
最后一部分只能是版本仓库的路径,不能是版本仓库的一个模块的路径。
CVS客户端基本操作使用导入 (import)设置版本仓库的初始内容
#cvs -d xx import -m "xx" module_name vendor-tag release-tag选项 -m的参数是对本次导入的一个注释。参数 vendor-tag和 release-tag只有对供方分支(vendor branch)进行版本控制时才会使用到,一般建议 vendor-tag设置为 none, release-tag设置为模块名。供方分支是指由他人进行修改和发布,但由自己进行使用的文件集合。经常是以一个库的形式存在。
CVS客户端基本操作
cvs import的例子#cvs -d xx import -m "import toplevels" . none toplevel将当前目录下的所有内容导入到版本仓库下
#cvs -d xxx import -m "import docs" doc none doc将当前目录下的所有内容导入到版本仓库的 doc目录下
CVS客户端基本操作使用 export导出 CVS版本仓库的内容
#cvs -d xx export [-r tag] [-d dir] module_name一般用于软件源码打包发布,因为导出的内容中不包含版本控制信息。
选项 -r的参数表示一个标签名, HEAD为一个特殊的标签名,表示版本仓库主干的最新状态。选项 -d的参数是一个目录名,表示将导出的内容存储到该目录,而不是存储到利用模块名新创建的一个子目录。
CVS客户端基本操作
cvs export例子
#cvs -d xx export -d all -r HEAD .将版本仓库中的所有内容导出到当前目录的子目录all,子目录 all将被自动创建。#cvs -d xx export -r HEAD fbset-2.1将版本仓库中的 fbset-2.1模块导出到当前目录的fbset-2.1子目录下,子目录 fbset-2.1将被自动创建。
CVS客户端基本操作
使用检出 (checkout)创建一个工作拷贝cvs -d xx checkout -d dir module_name
选项 -d表示在当前目录的子目录 dir下创建一个工作拷贝,而不是在以模块名为名称的子目录下创建一个工作拷贝。子目录都会被自动创建。
module_name表示一个模块名。当 module_name等于 .时,表示检出版本仓库中的所有内容。
CVS客户端基本操作cvs checkout的例子
#cvs -d xx checkout -d all .从版本仓库中检出全部的内容,在子目录 all下生成一个工作拷贝。#cvs -d xx checkout fbset-2.1从版本仓库中检出 fbset-2.1模块,在子目录fbset-2.1下生成一个对应的工作拷贝。#cvs -d xx checkout -d wmctrl wmctrl-1.07从版本仓库中检出 wmctrl-1.07模块,在子目录wmctrl下生成一个对应的工作拷贝。
CVS客户端基本操作
使用 cvs add和 commit 添加文件
#cvs add [-k kflag] files选项 -k的参数用于控制 CVS对添加的文件的内容进行关键词替换 (keyword substitution)。不建议使用这种特性。对文本文件使用 -k o,对二进制文件使用 -kb。
在添加一个文件前,确保该文件所在的目录已经纳入版本控制,否则需要先添加该目录。
CVS客户端基本操作
使用 cvs add 添加新目录
#cvs add dirs与添加新文件不同,添加新目录只需要使用 cvs add 即可,不需要再使用 cvs commit。因为 CVS实际上不对目录只对文件进行版本控制。
例如#cvs add scripts添加新目录 scripts
CVS客户端基本操作cvs add例子# cvs add -kb fbset-2.1/README添加文本文件,并且不进行关键词替换。#cvs add -kb fbset-2.1/manual.pdf添加二进制文件,并且不进行关键词替换。
添加完成后,该工作拷贝中文件的状态为:
CVS客户端基本操作
cvs add 例子"A"表示工作拷贝中新添加的文件,但该文件没有提交到版本仓库。需要使用 cvs commit来提交。
例子中没有使用全局选项 -d。因为当前在一个工作拷贝中进行添加操作,工作拷贝中记录有对应的版本仓库的 cvs root信息。
CVS客户端基本操作
取消新添加的文件
#cvs add script/monitor.sh#cvs remove script/monitor.sh
取消新添加的目录#cvs add cache/#rm cache
CVS客户端基本操作
使用 cvs commit提交修改
#cvs commit [-Rl] -m msg [files]修改包括对原有文件内容的修改、添加新文件、删除原有文件。选项 -R和 -l用于设置递归的提交。默认为递归的提交,即 -R。选项 -m的参数 msg是对当前的提交进行简要说明的文本。参数 files可以是一个 /多个文件名 /目录名,也可以为空,表示当前目录。
CVS客户端基本操作cvs commit例子
#cvs commit -m "add README" fbset/README将新文件提交 README到版本仓库。#cvs commit -m "clean up gcc warnings" fbset/fbset.c将修改后的 fbset.c提交到版本仓库。#cvs commit -m "add multilingual demo"将工作拷贝中的所有修改提交到版本仓库。#cvs commit -R -m "support input method" wmctrl将工作拷贝中的 wmctrl目录下的修改提交到版本仓库。
CVS客户端基本操作修改文件后,查看文件的状态
#cvs -qn update filesfiles参数可以是一个或者多个文件,也可以为一个或者多个目录,还可以为空,表示当前目录。
"A(Add)" 新增的文件"M(Modifiy)" 修改的文件"R(Remove)" 删除的文件"C(Conflict)" 冲突的文件"?(Unknown)" 未纳入版本控制的文件
CVS客户端基本操作cvs -qn update的例子
#cvs -qn update输出如下图
CVS客户端基本操作
cvs diff查看工作拷贝中的修改
#cvs diff [-Rl] -U 3 -p -N [files]选项 -R和 -l控制了是否递归,选项 -U 3 -p -N控制差异的输出格式。
cvs命令行不支持使用使用外部的差异比较程序来显示差异。
CVS客户端基本操作cvs diff例子#cvs diff -U 3 -p -N fbset-2.1/fbset.c
CVS客户端基本操作
cvs update 取消工作拷贝中的修改
#cvs update -C fbset-2.1/fb.h取消工作拷贝中对 fb.h所有的修改#cvs update -C wmctrl-1.07取消工作拷贝中 wmctrl-1.07目录下的所有修改#cvs update -C取消工作拷贝的所有修改
CVS客户端基本操作
cvs remove 删除文件和目录
#cvs remove [-f] [-Rl] files选项 -f表示先从工作拷贝中删除该文件,然后取消对该文件的版本控制。选项 -R和 -l设置了递归删除和非递归删除。
使用 cvs remove后,还需要使用 cvs commit将删除从工作拷贝提交到版本仓库。
CVS客户端基本操作
cvs remove的例子
#cvs remove -f lddbus/README删除 lddbus/README文件#cvs remove -f -R lddbus/.tmp_version删除 lddbus/.tmp_version目录
CVS客户端基本操作取消文件的删除
在使用 cvs rm后,使用 cvs add 取消删除#cvs rm -f fbset-2.1/fbset.c#cvs add fbset-2.1/fbset.c
在没有使用 cvs rm前,使用 cvs update 取消删除#rm lddbus/Makefile#cvs update lddbus/Makefile
通过取消目录下每一个文件的删除,来取消目录的删除。
CVS客户端基本操作
查看工作拷贝中文件的详细信息
#cvs status [-v] [-Rl] [files]使用选项 -v可以获取更为详尽的输出。选项 -R和 -l分别控制递归和非递归显示当前目录下的文件信息。#cvs status fbset-2.1/fbset.c
CVS客户端基本操作
cvs status 显示的文件状态
Up-to-date 工作拷贝中的文件没有修改,版本仓库中对应的文件没有更新Locally Modified 工作拷贝中的文件做了本地修改,版本仓库中对应的文件没有更新Locally Added 工作拷贝中增加了新文件Locally Removed 工作拷贝中删除了旧文件
CVS客户端基本操作
cvs status 显示的文件状态 ( 续 )
Needs Checkout/Needs Patch 工作拷贝中的文件没有更新,版本仓库中的对应文件进行了更新Needs Merge 工作拷贝工作的文件做了修改,版本仓库中对应的文件也做了修改Unresolved Conflict 将版本仓库的更新合并到工作拷贝时,出现了冲突,并且该冲突未解决
CVS客户端基本操作
cvs update 获取版本仓库的更新
#cvs -q update -P -d [-Rl]选项 -q用于去掉不必要的输出信息。选项 -d用于获取新创建的模块选项 -R和 -l用于控制更新过程递归与否。默认为递归的更新。选项 -P用于禁止空目录的获取。
CVS客户端基本操作
cvs update对工作拷贝的修改
可以通过 cvs update 输出的信息得到"U" 添加了一个文件"P" 修改了一个文件"C" 修改了一个文件,但在合并修改时存在冲突
对删除文件没有对应的标志,但是会提示 "xxx is no longer in the repository"来表示更新过程删除了该文件。
CVS客户端基本操作
cvs log 查看修改日志
#cvs log [-r[revisions]] [-Rl] [files]选项 -r的参数可以用于设置显示日志的修订版区域。 files可以为空,表示当前目录。默认是递归 的显示当前目录下的所有文件的修改日志。
CVS客户端基本操作
cvs log例子
#cvs log fbset-2.1/fbset.c显示 fbset.c文件的修改日志#cvs log -r1.3:1.6 fbset-2.1/fbset.c显示从修订版本号 1.3到 1.6, fbset.c的修改日志#cvs log递归显示当前目录下的所有文件的修改日志
CVS客户端基本操作
cvs log的输出主要内容的格式如下图:
revision表示对应的修订版本号state 表示当前文件的状态。 "Exp" 说明依然存在, "dead"表示该文件被删除了。lines表示添加和删除的行数。没有 lines时,表示在对应的修订版本添加了该文件。
CVS客户端基本操作
文件重命名
#cp script/list.py script/files.py#cvs remove -f script/list.py#cvs add script/files.py#cvs commit -m "xxx" script/list.py script/files.py
CVS不能很好的支持文件的重命名。使用上面的重命名方式,新的文件没有 " 继承 " 重命名以前的修改日志信息。
CVS客户端基本操作
目录重命名
依次对目录下的每一个文件进行重命名即可。#cp -rP cache glib#rm -fr glib/CVS#cvs rm -f cache#cvs add glib glib/glist.c glib/glist.h#cvs commit -m "rename cache to glib" cache glib#cvs update -P
CVS客户端基本操作
cvs update"撤销 "已经提交的修改
并不是指将一个或多个提交从修改记录中删除,而是指在工作拷贝中取消这些提交所做的修改,并且提交工作拷贝中发生的修改。这样就到达了 "撤销 "已经提交的修改的目的。
CVS客户端基本操作
撤销提交修改的例子
glib/glib.h和 glib/glib.c当前修订版本号为 1.3。#cvs update -j 1.3 -j 1.2 glib/glib.h glib/glib.c#cvs commit -m "revert the change of 1.3" glib/取消修订版本号 1.3所做的修改, " 回退 "到 1.2时文件的状态,提交后新的修改版本号为 1.4。
CVS客户端基本操作
cvs update 获取旧的修订版本的文件内容
#cvs update -p -r revision file > old_filerevision表示需要的修订版本号, file为该文件的名称, old_file为保存旧的修订版本号的文件内容的文件名。可以用它来恢复删除的文件。
#cvs update -p -r 1.3 glib/glib.c > glib.c_1.3获取修订版本为 1.3时的 glib/glib.c文件内容,并且保存到 glib.c_1.3.
CVS客户端基本操作
标签
一种为仓库版本中的全部或者部分文件生成快照的方法。关于标签的信息保存在版本仓库中,而不是工作拷贝中。
CVS客户端基本操作创建标签
#cvs tag [-c] [-Rl] tag_name [files]为工作拷贝中处于特定修订版本号的所有文件或者部分文件,创建一个标签。标签名必须由字母开始,只能包含字母、数字、连字符 (-)和下划线 (_)选项 -c表示对将包含到标签中的文件进行检查,查看它是否存在没有提交的修改。若有,则终止创建
一般是对版本仓库的全部内容或者一个模块创建分布标签或者临时标签。不建议修改标签的内容。
CVS客户端基本操作
创建标签的例子
#cvs tag -c release_glib_00_01_00 glib为 glib模块创建一个发布标签,发布 0.1.0版本。#cvs tag -c release_all_01_00_00为全部文件创建一个发布标签,发布 1.0.0版本。#cvs tag -c snapshot_2010_11_03为所有内容创建一个临时标签#cvs tag -d snapshot_2010_11_03删除临时标签
CVS客户端基本操作
查看已创建的标签
#cvs status -v file可以显示出为整个版本仓库创建的标签和为 file所在的模块创建的标签。
#cvs status -v glib/glist.c查看全局标签和模块 glib的标签。
CVS客户端基本操作
特殊的标签名
BASE只与当前的工作拷贝相关。它表示工作拷贝中所有文件在剔除了本地修改时的状态。
HEAD只于版本仓库相关。它表示当前版本仓库的主干所有文件的最新状态。
CVS客户端基本操作获取发布标签的内容
#cvs -d xx co -r release_all_01_00_00 -d all-1.0.0 .获取发布标签 release_all_01_00_00的内容,检出到all-1.0.0目录。无法提交对检出的标签内容的修改,因为该内容被粘住了 (sticky)。
#cvs -d xx co -r release_glib_00_01_00 -d glib_0.1.0 glib获取发布标签 glib_release_00_01_00的内容,检出到 glib-0.1.0目录
CVS客户端基本操作
临时标签
将工作拷贝 " 回退 "到一个临时标签。#cvs update -C#cvs update -j HEAD -j snapshot_xxx#cvs commit -m "revert to snapshot_xxx"将工作拷贝回退到 snapshot_xxx。
CVS客户端基本操作分支
分支提供了进行并行开发的机制。在主干上开发新版本,而在分支上进行旧版本的维护或者添加一个复杂的新功能。两者之间不会相互干扰。分支的相关信息也是保存在版本仓库中,而非工作拷贝中。
CVS客户端基本操作创建维护分支
在发布一个新版本时创建一个与该版本对应的一个维护分支,在该分支中不再加入新功能,只加入缺陷修正。创建一个维护分支后,需要再创建一个对应的初始的发布标签。随着后续缺陷修正的加入,还需要创建后续的发布标签来发布新的子版本。#cvs tag -b branch_00_01创建名为 branch_00_01的分支,维护 0.1版本。#cvs -d xx rtag -r branch_00_01 release_00_01_00创建 0.1.0版本的标签,发布 0.1.0版本。
CVS客户端基本操作
创建功能分支
当需要在当前的新版本中添加复杂的功能时,有可能需要使用功能分支,而不是直接在主干中实现该功能。因为使用功能分支可以避免干扰其它开发者在主干上的开发。
创建方法与维护分支是相同的。#cvs tag -b branch_fb_backend创建名为 branch_fb_backend的功能分支
CVS客户端基本操作
查看已创建的分支
与查看已创建的标签的过程相同。#cvs status -v file可以显示出为整个版本仓库创建的分支和为 file所在的模块创建的分支。
#cvs status -v glib/glist.c
CVS客户端基本操作
检出分支
为了向分支提交修改,需要从版本仓库检出一份分支的工作拷贝。
#cvs -d xx checkout -r branch_00_01 -d 0.1 .将维护分支 branch_00_01检出到子目录 0.1
CVS客户端基本操作
将维护分支的缺陷修正合并到主干
为了支持多次合并,需要再创建一个标签,该标签对应于维护分支中上一次合并到主干的截止点。每一次合并都需要更新该标签。#cvs rtag -r release_00_01_00 cursor_00_01_merge#cd trunk#cvs update -j cursor_00_01_merge -j branch_00_01#cvs commit -m "merge bug fix from 0.1 to trunk"#cvs rtag -r branch_00_01 -F cursor_00_01_merge .
CVS客户端基本操作
将主干的最新修改合并到功能分支
依然需要建立一个标签,来指向主干中的一个点,表示上一次合并时的截止点。在合并后需要更新该标签。under trunk#cvs tag -b branch_fb_backend#cvs tag cursor_fbbe_trunk_mergeunder fb backend branch#cvs update -j cursor_fbbe_trunk_merge -j HEAD#cvs commit -m "merge from trunk"#cvs rtag -F -r HEAD cursor_fbbe_trunk_merge
CVS客户端基本操作
将功能分支的添加的功能合并到主干
因为功能分支不断的将主干的修改合并进行,所以到最后添加的新功能就是主干的最新修订版本和功能分支的最新修订版本的差别。#cvs update -j branch_fb_backend -j HEAD #cvs rtag -d cursor_fbbe_trunk_merge
CVS客户端基本操作
删除分支
维护分支和功能分支的区别还在于维护分支不会被删除,而功能分支在功能完成后应该被删除掉。#cvs -d xx tag -B -d branch_fb_backend
CVS客户端基本操作
定义忽略文件
在运行 import/update/release时, CVS将忽略那些匹配忽略文件模式的文件。 CVS有默认的忽略文件模式列表。
使用工作拷贝中模块目录中的 .cvsignore来自定义忽略文件模式。该模式只对当前目录下的文件 /目录有效,也不会递归到子目录。忽略模式不能指定路径。
CVS客户端基本操作
查看版本仓库已定义的 CVS模块名#cvs -d xx checkout -c
#查看当前位于的分支#cvs status file | grep "Sticky Tag"
none和 HEAD都表示在主干上。
CVS客户端基本操作
查看关键词替换标志#cvs log -t file | grep "keyword substitution"
修改关键词替换标志#cvs admin -ko text_files#cvs update text_files
#cvs admin -kb binary_files#cvs update binary_files
CVS的缺点
整体的角度
正在被淘汰的版本控制软件。
不容易使用。递归的添加、文件类型的区分、 update子命令能完成的事情、查看所有标签和分支。
权限控制。不能针对每一个目录 /模块来设置权限
CVS的缺点
软件开发的角度
修订版本号不能表示软件的整体状态
不支持原子提交。可能使版本仓库处于不一致状态
缺乏对目录的版本控制。添加多层新目录很麻烦
缺乏对重命名和复制的 " 继承修订历史 "的支持
CVS的缺点
文档控制的角度
对二进制文件没有进行差异化存储,而是完整的存储了每一个修订版本。
CVS的替代者Subversion(SVN)
目的就是修正 CVS 没有解决的问题,取代 CVS。
稳定、成熟。易于使用。文档齐全。
被代码托管商广泛采用。比如 google code 、sourceforge.net、 berliOS developer、 Gna等。
提供了从 CVS 向 SVN 转化的工具 cvs2svn等。
详情 http://subversion.apache.org
建议
使用 Subversion,而不是正在被淘汰的 CVS。