每个开发人员应该知道的基本清晰概念是什么?
每个开发者都应该知道的Clearcase版本控制系统的核心概念是什么?
核心概念?
-
集中的(重复的)VCS :ClearCase位于集中的VCS世界(一个或几个“集中式”回购或VOBS-版本对象库 – 每个开发者必须提交提交)和分布式VCS世界之间。
但它也支持“复制”模式,允许您在远程站点复制回购(MultiSite ClearCase),发送增量和pipe理所有权。 (附带的许可证费用相当陡峭)
这不是一个真正的“分散”模型,因为它不允许并行的并发演变:分支被掌握在一个VOB或另一个VOB中; 您只能在主VOB中签入在那里掌握的分支,尽pipe您只能以任何副本访问任何分支。 -
线性版本存储 :每个文件和目录都有一个线性历史logging; 他们之间没有直接的关系,如DAG VCS( Directed Acyclic Graph ),其中文件的历史链接到链接到提交的目录之一。
这意味着- 当您比较两个提交时,您必须比较所有文件和目录的列表以查找增量,因为提交在文件或目录中不是primefaces的,意味着对于组成的所有文件的所有更改没有单一名称逻辑三angular洲。
-
这也意味着合并必须通过历史探索find共同的基础贡献者 (不总是与共同的祖先一样)(见下一点)。
(Git处于这个领域的另一端,既是分散的,也是面向DAG的:
- 如果图的节点与另一个提交的节点具有相同的“id”,则不必进一步探索:所有的子图保证是相同的
- 两个分支的合并实际上是合并了一个DAG中的两个节点的内容:recursion并且很快find一个共同的祖先)
-
3-way合并 :合并两个版本,ClearCase必须在其线性历史logging中find一个共同的贡献者, 对于复杂版本树 (branch / sub-branch / sub-sub / branch,…)可能相当长 ,基本的ClearCase合并命令合并了一个文件或目录,但它不是recursion的。 它只影响单个文件,或者没有文件的单个目录(
ct findmerge
是recursion的) -
以文件为中心 (相对于其他最近的VCS更多以存储库为中心):这意味着提交是逐个文件而不是“已修改文件集”:事务处于文件级别。 提交的几个文件不是primefaces的。
(几乎所有其他的现代工具都是“以存储库为中心的”,具有primefaces提交事务,但是像RCS,SCCS,CVS和其他大多数旧系统的第一代系统没有这个function。 -
id-managed :每个文件和目录都有一个唯一的ID,这意味着它们可以随意更名:由于ID保留为“元素”,它们的历史不会改变。 再加上一个目录将在其历史中检测到任何文件的添加/抑制。 当一个文件被“删除”(
rmname
)时,它不知道它:只有目录被通知,并在其历史中创build一个新的版本,其中有一个子元素列表不包括该文件被删除。
(创build两个具有相同大小和内容的文件,它们将在Git中获得相同的ID – SHA1密钥 – 并且只会在Git仓库中存储一次,而ClearCase中则不会。
另外,如果在两个不同的分支中创build两个具有相同path和名称的文件,则它们的id不同意味着这两个文件将永远不会合并:它们被称为“ 邪恶的双胞胎 ”)
-
分支机构是一stream的公民 :大多数VCS认为分支和标签是一样的:历史上的一个新的线性历史logging可以增长(分支)或从附加说明(标签)的地方开始。
对于ClearCase来说,分支是引用版本号的一种方式。 任何版本号都从0开始(只在ClearCase中引用)到1,2,3等等。 每个分支可以包含一个新的版本号列表(0,1,2,3)。
这与其他版本号唯一并且不断增长的系统(如SVN中的版本)不同,或者是唯一的(如Git中的SHA1键)。 -
path访问 :要访问文件/目录的某个版本,您需要知道其扩展path(由分支和版本组成)。 它被称为“扩展path名称”:
myFile@@/main/subBranch/Version
。
(Git通过id – 基于SHA1的 – :版本[或提交],树[或版本的目录]和blob [或文件的版本,或者文件的内容 ]引用所有内容 。它是“id访问”或“id引用”。
对于ClearCase,id指的是一个“元素”:一个目录或一个文件,无论它的版本是什么。)
-
悲观锁和乐观锁 :(在ClearCase中保留或无保留的签出):即使悲观锁(保留结帐)也不是真正的悲观锁,因为其他用户仍然可以签出该文件(尽pipe处于“非保留模式”):他们可以改变它,但将不得不等待第一个用户提交他的文件(签入)或取消请求。 然后他们将合并他们的同一文件的结帐版本。
(注意:“保留”结账可以解除locking,并由所有者或pipe理员保留) -
便宜的分支 :分支不会触发所有文件的副本。 它实际上什么都不触发:任何不结账的文件都会留在原来的分支中。 只有已修改的文件将其新版本存储在声明的分支中。
-
平面文件存储 :VOB以简单文件的专有格式存储。 这不是一个简单的查询语言的数据库。
-
本地或networking工作区访问 :
- 本地工作区是通过结帐到硬盘(快照视图的“更新”)。
- networking工作区是通过dynamic视图,通过networking(无本地拷贝,即时访问)和本地文件(检出或私人文件)结合版本文件和目录。 远程(版本化)和本地(私有)文件的组合允许dynamic视图显示为典型的硬盘驱动器(而实际上任何“写入”文件都存储在关联的视图存储器中)。
-
集中式驱逐存储 :[查看]存储是为了保存一些数据,避免与中央参考进行一些或任何的沟通。
一个工作区可以有:- 分散的存储空间:像
.svn
子目录一样 - 一个集中式存储:就像ClearCase中的视图存储一样,它们包含有关视图显示的文件的信息,并且该存储对视图是唯一的。
- 被驱逐的存储:存储不是视图/工作区本身的一部分,但可以位于计算机的其他位置,甚至在LAN / WAN外部
- 分散的存储空间:像
(Git本身没有“存储”,它的.git
实际上是所有的存储库!)
- 面向元数据 :任何“键值”都可以附加到一个文件或一个目录中,但是这对数据本身并没有被历史化:如果值发生了变化,它就会覆盖旧值。
(这意味着这个机制实际上比SVN的“属性”系统更弱,其中属性可以有一个历史;
Git另一端对元数据不太感兴趣)
- 基于系统的保护 :所有者和与文件/目录或存储库相关的权利基于底层系统的权限pipe理。 在ClearCase中没有适用的帐户,用户组直接基于Windows或Unix现有组(这在异构环境中非常具有挑战性,Windows客户机和Unix VOB服务器是相当具有挑战性的!)
(SVN更像“基于服务器”的保护,Apache服务器可以获得第一级保护,但是必须使用钩子来完成,才能拥有更好的权限。
Git没有直接的权限pipe理,必须在存储库之间的推送或拉取过程中通过挂钩进行控制)
-
可用钩子 :任何ClearCase动作都可以成为钩子的目标,称为触发器。 它可以是预先或后期操作。
-
CLIpipe理 :cleartool是可以从中进行所有操作的命令行界面。
ClearCase是一个使用的野兽。 慢,越野车,而且昂贵。 我已经做了一些应对CC的事情:
- 请务必在办理入住手续时提出宝贵的意见
- 使用一个通用的configuration规范,不要经常更改它。
- 切勿尝试通过VPN或慢速networking连接使用CC。
- 启动时closuresCC医生的加载。
- 不要将文件移到不同的目录。
- 安排每个文件至less2分钟登记。
- 快照视图较慢,但dynamic视图较慢。
- 早期制定检查的发展习惯,因为保留的文件和合并是痛苦的。
- 让所有的开发人员在默认情况下检查未保留的文件。
我们已经使用了CC超过十五年了。 它有很多好的function。
我们所有的发展都是在分行上完成的 我今天创造了一对夫妇,进行了几个不同的变化。 当我进入分支机构时,我有一个同事审查这些变化,然后合并回到/ main / LATEST – 这正好是我的工作需要去的地方。 如果是在分支上发行的版本较旧,那就不会更难了。
我的临时分支合并是全自动的; 没有人改变了我工作的文件,而我把他们签出。 尽pipe默认情况下checkout是保留的(locking),但您可以随时取消checkout,也可以自动创buildcheckout。 当更改需要多天时,我的临时分支与主分支的重新同步很容易,通常是自动的。 mergetool是好的; 对我来说最大的问题是我的服务器机器距离我的办公室(或家里)有1800英里左右,所以X在这个远处有点慢(但不是难以忍受)。 我没有使用一个更好的mergetool,但是这可能不是很多,因为我没有使用任何其他graphicsmergetool。
视图(dynamic视图)在我们的设置上很快。 我没有使用快照视图,但是我不能在Windows上工作(我们的团队在Windows上使用快照视图;我不清楚为什么)。 我们有复杂的分支系统,但主要的开发是在/ main / LATEST上完成的,并且发布工作在分支上完成。 在GA之后,维护工作在一个特定版本的分支上完成,然后合并到/ main / LATEST(通过任何中间版本)。
CC确实需要优秀的pipe理员 – 我们拥有这些pipe理员,并且很幸运。
CC不是微不足道的,尽pipe现在我觉得CC是令人畏惧的,对于那些没有使用CC的人来说,它是令人生畏的。 但是基本的东西是一样的 – 结帐,更改,签入,合并,分支等等。 目录可以谨慎分支 – 当然版本控制。 这是非常宝贵的。
我没有看到办公室随时从CC切换。
embedded式版本号 – 好还是坏?
我写了:
我在CC中遇到的最大问题是,它没有将版本号embedded到源文件中,这是git也有的问题,AFAICT。 我可以半看到为什么; 不过我不确定我是否愿意放弃这种可追踪性。 所以,我的大部分个人工作仍然使用RCS(甚至不包括CVS)。 有一天,我可能会转而使用git,但这将是一个颠簸,需要大量的工作来重新configuration(SCCS和)RCSconfiguration的版本系统。
作为回应,@VonC指出:
我们一直认为这种做法是邪恶的(把元数据信息混合成数据),引入“合并地狱”。 另请参见如何在Java文件中获取Clearcase文件版本 。 当然,如果使用适当的合并pipe理器 ,则可以使用RCS关键字replace触发器( Clearcase Manual:Checkin Trigger Example )。
这个讨论暴露了几个问题,他们都混在一起。 我的观点接近过去,但有一个理由背后,我会花时间写下来(生活搞砸了 – 可能需要一些编辑才能完成)。
背景
我在1984年学习了SCCS,关于RCS发布的时间(我相信1983),但SCCS在我的机器上,互联网刚刚起步。 在90年代中期,我很不情愿地从SCCS迁移到RCS,因为SCCS的date格式使用了两年多的时间,SCCS是否能及时得到普遍的固定是不明确的。 在某些方面,我不喜欢RCS和SCCS一样多,但有一些好的一面。 在商业上,我的雇主在1995年年中使用了SCCS,但是他们从1994年初开始转向Atria ClearCase,一次处理单独的产品。
早期ClearCase触发器实验 – 合并地狱
我们的项目后来迁移了,当时已经有了一些CC的经验。 部分原因是我坚持这样做,我们通过签入触发器在源文件中embedded版本控制信息。 这持续了一段时间,但只有一段时间,因为正如VonC所说,它导致了地狱的融合。 麻烦的是,如果一个带有tag / main / branch1 / N的版本与common base / version / main / B中的/ main / M合并,那么这些文件的提取版本将包含一个单独的行,冲突。 而且这个冲突必须手动解决,而不是自动处理。
现在,SCCS有ID关键字。 ID关键字采用两种格式,一种用于正在编辑的文件,另一种用于未正在编辑的文件:
Edit Non-Edit %I% 9.13 %E% 06/03/09 %Z% @(#) %M% s.stderr.c
如果您试图将SCCS文件的可编辑版本(使用%x%表示法)进行三方合并,则在包含元数据的行上不会发生冲突,除非您更改了这些行上的元数据(例如,通过从US-风格%D%date到英式风格%E%date – SCCS不支持ISO风格2009-03-15date作为标准。)
RCS也有一个关键字机制,关键字也有两种格式,一种是针对尚未插入到RCS中的文件,另一种针对那些具有以下function的文件:
Original After insertion $Revision$ $Revision: 9.13 $ $Date$ $Date: 2009/03/06 06:52:26 $ $RCSfile$ $RCSfile: stderr.c,v $
区别在于关键字和':'之后的'$',空格,文本,空格,最后是'$'。 我没有和RCS做足够的合并,以确定它是如何处理关键字信息的,但是我注意到,如果它把扩展和“收缩”符号同等对待(不pipe扩展材料的内容如何),那么合并发生没有冲突的情况下,将合同中的符号留在合并的输出中,当签入后检索结果文件时合适的扩展。
ClearCase问题是没有适当的合并pipe理器
正如我在讨论SCCS和RCS时所指出的那样,如果以正确的(合同的或可编辑的)格式对关键字进行三方合并,则不存在合并冲突。
CC的问题(从这个angular度来看 – 显然,CC的实现者不同意)是缺less处理关键字的系统,因此也缺less合适的合并pipe理器。
如果有一个处理关键字的系统和一个合适的合并pipe理器,那么:
- 系统会自动将元数据embedded到适当标记处的文件中。
- 在合并时,系统将认识到具有元数据标记的行不会相互冲突,除非标记改变不同 – 它会忽略元数据内容。
其缺点是它需要一个特殊的差别工具来识别元数据标记并专门处理它们,或者它要求提供给差异工具的文件是规范化的(元数据标记被简化为中性forms – $ Keyword $或RCS和SCCS条款中的%K%)。 我相信这一点额外的工作是不被支持的原因,在这样一个强大的系统中,我总觉得这是短视的。 我对RCS或SCCS符号没有特别的依赖 – SCCS符号在某些方面更容易处理,但它们在本质上是等效的 – 可以使用任何等同的符号。
为什么我仍然认为文件中的元数据是好的
我喜欢在源代码中包含元数据,因为我的源代码(而不是我的雇主的源代码)分布在源代码控制系统的主体之外。 也就是说,它大部分是开源的 – 我向所有人和所有人开放。 如果有人在文件中报告问题,特别是在他们修改过的文件中,我认为知道他们从哪里开始是很有帮助的,而这是由源文件中的原始元数据表示的。
在这里,SCCS与RCS相比具有优势:SCCS关键字的扩展forms与常规文本无法区分,而RCS关键字继续看起来像关键字,所以如果其他人将材料导入到它们自己的RCS存储库中,则它们的元数据将取代我的元数据,这个问题在SCCS中不会以同样的方式发生(另一个人不得不重写元数据)。
因此,即使有人拿走了我的源代码块并对其进行修改,通常也有足够的标签来标识它的来源,而不是让我猜测它是基于哪个版本。 而这反过来又使我们更容易看出问题的哪些部分是由我制定的,哪些部分是他们制造的。
现在,在实践中,开源的工作方式,人们不会像你想象的那样迁移代码。 他们倾向于紧贴发布的版本,只是因为在下一次正式发布时偏离太贵。
我不知道你应该如何确定源自你的工作的源代码的基本版本,并从那以后进行了修改。 find正确的版本,似乎是做到这一点的关键,如果在代码中有指纹,那么它可以更容易。
所以,这是我为什么喜欢在源文件中embedded版本信息的温和总结。 这在很大程度上是历史的 – SCCS和RCS都做到了,我喜欢他们这样做的事实。 它可能是古代的遗物,是DVCS时代的一个告别的东西。 但是我还不完全相信。 但是,可能还需要更多的文章来解释我的发布pipe理机制的来龙去脉,看看我为什么要这样做。
推理的一个方面是关键文件,如“stderr.c”和“stderr.h”,基本上都是我的程序使用的。 当我发布一个使用它的程序时,我只是确保我有最新的版本 – 除非有一个接口更改需要一个后退版本。 我有一段时间没有这个问题了(我在2003年进行了一次系统化的重命名,这导致了一些过渡性的麻烦,但Perl脚本允许我很容易地实现重命名)。 我不知道有多less个程序使用这个代码 – 大约在100到200之间是合理的猜测。 今年的一系列变化(9.x系列)仍然有些猜测; 我还没有决定是否保留它们。 他们也是内部的实施,不影响外部接口,所以我不必下定决心。 我不知道如何处理使用混帐。 我不希望将库代码构build到必须安装的库中,然后才能构build我的软件 – 这对于我的客户来说过于繁琐。 因此,每个程序将继续分发一个库代码副本(一种不同的繁琐),但只有程序需要的库代码,而不是整个库。 我select每个程序使用哪个库函数。 所以,我不会输出一个完整的子树, 实际上,涵盖库代码最后更改的提交通常与涵盖程序最后更改的提交完全无关。 我甚至不确定git是否应该为库使用一个存储库,使用它的程序是另一个存储库还是一个通用的较大的存储库。 直到我明白了这一点之后,我才会迁移到git。
好 – 足够诡异。 我为我工作的东西; 这不一定适合每个人。 它对VCS没有特别的要求 – 但是它确实需要在文件中embedded版本元数据,CC和Git以及(我认为)SVN都有这个问题。 这可能意味着我是一个有问题的人 – 对失去的过去的沉思。 但我重视过去所提供的。 (我可以避开它,因为我的大部分代码都没有分支,我不确定分支会有多less差异。)
Eric的Source Control HOWTO是一个独立于工具的伟大指南。
我在6年的较好的一部分工作,一般认为它是可以忍受的。 它确实有一定的学习曲线,但是一旦你习惯了这些怪癖,你就可以顺利地进行工作。 知道自己在做什么的非常称职的CCpipe理员对于除了微不足道的设置之外的任何事情都是必不可less的。 除非你有一个,否则人们会遇到问题,很快就会有关于“ClearCase”问题的讨论。 那么pipe理层将不得不通过转向其他方式进行干预,这只会浪费所有参与者的时间。 CC不是一个糟糕的产品,有时只是很难理解。
这里有几个我认为重要的概念,其中一些并不是只有CC才有的 –
- 退房不同于常规的CVS类似的退房概念。 当您签出时,您将文件locking,直到您签入。
- 移动文件没有问题。 事实上这工作完美无瑕。
- 版本树对于理解文件发生了什么是必不可less的。 他们对于活动文件可能会相当混乱,但是当你习惯于观察它们的时候,它就变成了一个非常有用的工具,而在SVN等其他源代码控制工具(某种程度上)方面却很缺乏。
- 在任何情况下都不要使用dynamic视图。 这不值得。
- 在做一个新的分支,stream或项目之前,build议你的pipe理员确保你创build的是真正最能为你服务的东西。 开始一个新的代码库时,请确保从一开始就提前计划,从而获得stream和项目的布局。 如果可能的话,稍后改变是一个真正的头痛。
- 微调用户权限,设置常用事件触发器,防止常见错误或执行策略。 服务器是非常可configuration的,而且大多数您遇到的问题可能是一个合理的解决scheme。
- 教育开发人员从基本概念到推进运营。 一个能够find问题的用户可以使用cleartool降低pipe理员的负担。
- 不要留下悬垂的溪stream和景色。 当开发人员离开项目时,有人要删除他在机器上的所有视图,并删除所有的私人stream。 不保持你的服务器清洁将导致…它是肮脏的,随着时间的推移,缓慢。 当您在所有stream和视图上执行“查找所有结帐”时,不应该看到不再存在的用户签出的文件。
- 对子分支机构实施“总是重新投放前”的政策,以避免人们在交付与最近的变化相冲突的代码时“打破整合stream”。
- 持续集成 – 当每个开发人员或团队在自己的分支上工作时,不要让整合stream停滞不前。 每X次授权一次,如果不能实现稳定的变化,每个人都必须尽快兑换最新的整合基准。 这确实很难做到,特别是对于大型项目来说,但是另一个select是“整合地狱”,在月底之前没有人做任何事情,而一些可怜的草地试图使所有的变化都合在一起
如何在ClearCase上使用git!
- Git后台,在盖子和下来低
- ClearCase在全球范围内,Git本地
- Git的Clearcase ,git-cc桥
在我看来,分支和合并是任何源代码pipe理系统中最重要的概念(当然,在版本pipe理本身旁边)。
一旦你明白了如何做到这一点(Clearcase做得非常好,即使我们做了很小的改变,像一个分支和重新合并,而不是我曾经用RCS或CVS做过的事情),你会发现你的生活变得容易很多
不知何故,但是 – 我几乎不知道对ClearCase满意的开发人员。 我被告知它应该有复杂的function,但作为一个svn和git用户,我不可能想到我在git或subversion中错过的东西。 所以这就是ClearCase应该知道的事情 – 大多数开发人员都非常乐意使用Subversion或git这样的简单工具(是的,即使是git也比较容易掌握)。即使在我知道如何完成ClearCase中最简单的任务之后,不断的感觉ClearCase不利于我,而不是我。
我已经使用Clearcase和SVN成功完成了一些大中型项目。 两者都是很好的工具,但使用它们的团队需要logging过程。 创build一个描述如何使用版本控制系统的过程。
1)为您的版本控制系统查找或创build最佳实践文档。 这里是一个颠覆 ,适应你的ClearCase进程。 所有开发者都必须遵守相同的游戏计划。
基本上决定你是否要“总是分支”或“永不分支”。
永不分支计划:
- 永不分支的scheme是什么SourceSafe使用的文件在结帐时被locking,并在签入期间成为可用。 这个scheme对于小型(1或2个开发者)团队项目来说是可以的。
始终分行计划:
- 始终分支机制意味着开发人员为每个bug修复或function添加创build分支。 这个scheme需要用于大型项目,具有领导者(buildmeister)的项目,他们pipe理什么样的变化被允许进入/ clear / SVN中的/ main / LATEST。
- 总是分支机制意味着你可以检查经常没有打破构build的恐惧。 只有在修补程序或function完成并将其合并到/ main / LATEST之后,才能破坏构build。
“需要时分支”是一个妥协scheme,可能对许多项目来说效果最好。
2)与Clearcase(和Subversion),你必须学会合并 – 合并是你的朋友。 学习使用Clearcase的合并function,或使用Beyond Compare或emacs-diff等工具。 如果你的项目模块化程度很好(很多小的解耦文件),在合并过程中你将会受益较less(或没有)冲突。
3)享受。
如果您使用ClearCase,请确保使用随附的UCM和复合组件。
它使所有的分支/合并毫不费力。 我正在谈论主要的重组分支机构,这些分支机构运行了6个月,涉及成千上万的更改,包括目录重命名,文件重命名等,自动解决99.9%的三angular洲问题。
另外,我们只使用SnapShot视图,而不是dynamic视图。 我们的快照视图加载速度比您可以从networking驱动器拖放(Windows)相同的源代码树快。
关于UCM唯一的抱怨就是历史不能跨越组件。 如果将组件分成多个新组件,则每个新组件都从/ main / 0开始。
你如何在你的项目上实现版本控制工具取决于你的项目规模和范围和团队的早期经验。 ClearCase是大型项目开发人员和项目规模的绝佳工具。 使用版本控制工具来pipe理分支是非常重要的前景之一。 没有分支和合并它是您的项目生命周期中的蛋糕步行。 但是你不能为了合并而离开,因为它可以让你locking和奇妙的并行开发。
有一个非常方便的命令cleardescribe
是有用的很多次。 可以用来获取标签和分支的细节。 语法是:
cleardescribe lbtype:<LABELNAME>@\<VOB-NAME> cleardescribe brtype:<BRANCHNAME>@\<VOB-NAME>
具体来说,这可以让您知道标签已应用于哪个分支,哪个分支是分支问题的父分支。