版本控制

版本控制

计算机术语
版本控制(Revisioncontrol)是一种软体工程技巧,籍以在开发的过程中,确保由不同人所编辑的同一档案都得到更新。版本控制用户会经常说他们“已提交更改”;这表示他们对各自文件的工作副本做了更改,并将这些更改提交到存储库。版本控制透过文档控制(documentationcontrol)记录程序各个模组的改动,并为每次改动编上序号。版本控制的最简单方法是在每一个公布的需求文档的版本应该包括一个修正版本的历史情况,即已做变更的内容、变更日期、变更人的姓名以及变更的原因并根据标准约定手工标记软件需求规格说明的每一次修改。你可以把一个版本控制系统(缩写VCS)理解为一个“数据库”,在需要的时候,它可以帮你完整地保存一个项目的快照。当你需要查看一个之前的快照(称之为“版本”)时,版本控制系统可以显示出当前版本与上一个版本之间的所有改动的细节。[1]
    中文名:版本控制 外文名:Revision control 所属学科:软件工程 类别:软体工程技巧 隶属:软体工程 功能:追踪文件的变更等 应用:软件开发 常用工具:CVS、SVN等

基本定义

版本控制透过文档控制(documentationcontrol)记录程序各个模组的改动,并为每次改动编上序号。这种方法是工程图(engineeringdrawings)维护(maintenance)的标准做法,它伴随着工程图从图的诞生一直到图的定型。一种简单的版本控制形式,例如,赋给图的初版一个版本等级“A”。当做了第一次改变后,版本等级改为“B”,以此类推等等。

相关系统

1.软件系统的版本控制是指可以自行运行的各子系统的版本控制。

2.软件系统的版本号由评测小组的人员确定,由评测小组进行版本控制工作。

3.软件系统的版本号由3部分构成,即主版本号+次版本号+修改号。主版本号1位,只有当系统在结构和功能上有重大突破改进后才发生变化;次版本号有2位;修改号8位,采用提交时的日期,当系统进行任何修改后,包括数据库结构发生变化,修改号都要随之改变。例如:Ver3.31.19990317

4.各子系统的版本号独立。

5.各软件系统应该有显示详细版本号的功能。例如help菜单下的about功能。系统提交存档时,评测服务部要进行版本号检查。

6.新系统开发完成、或已存档的系统进行修改,修改完成后,进行提交存档时,由评测评测小组系统分析工程师确定新版本号、或更改版本号。

7.软件系统,产生新的版本后,老版本的软件系统是否继续保存,取决于以下条件:

a.老版本的系统如果有客户还在使用,在客户升级以前,必须继续保存。

b.老版本的系统已经没有客户使用了,并且新版本的系统已经把老系统的文档完整地升级过来,这样可以删除或复盖老版本的系统资源。

c.对于要删除或复盖的老版本系统,可以统一备份起来。

本地系统

许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。这么做唯一的好处就是简单,不过坏处却不少:有时候会混淆所在的工作目录,弄错了文件丢了数据就没了退路。

为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异。

其中最流行的一种叫做rcs,现今许多计算机系统上都还看得到它的踪影。甚至在流行的MacOSX系统上安装了开发者工具包之后,也可以使用rcs命令。它的工作原理基本上就是保存并管理文件补丁(patch)。文件补丁是一种特定格式的文本文件,记录着对应文件修订前后的内容变化。所以,根据每次修订后的补丁,rcs可以通过不断打补丁,计算出各个版本的文件内容。

集中化的系统

接下来人们又遇到一个问题,如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统(CentralizedVersionControlSystems,简称CVCS)应运而生。这类系统,诸如CVS,Subversion以及Perforce等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法。

这种做法带来了许多好处,特别是相较于老式的本地VCS来说。现在,每个人都可以一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限,并且管理一个CVCS要远比在各个客户端上维护本地数据库轻松容易得多。

事分两面,有好有坏。这么做最显而易见的缺点是中央服务器的单点故障。若是服务器当机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。

如果中央服务器的磁盘发生故障,并且没做过备份或者备份得不够及时的话,还会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,被客户端提取出来的某些快照数据除外,但这样的话依然是个问题,你不能保证所有的数据都已经有人提取出来。本地版本控制系统也存在类似问题,只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新信息的风险。

分布式系统

于是分布式版本控制系统(DistributedVersionControlSystem,简称DVCS)面世了。在这类系统中,诸如Git,Mercurial,Bazaar还有Darcs等,客户端并不只提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。

更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程,比方说层次模型式的工作流,这在以前的集中式系统中是无法实现的。

详细内容

版本控制包括两个方面:保正人人得到的是最新的版本,记录需求的历史版本。

如果有专门的需求管理商业工具可以助您一臂之力,由于我并没有条件试用所有的需求管理工具,能够向大家推荐的只有瑞理公司的RequisitePro,推荐的一个重要原因是它能够把需求和瑞理的其他工具如Rose、TeamTest等联系起来,从而实现需求链。

能够借助工具将需求自动化固然很好,不过,工具使用不当也不会提高生产效率。需求管理的工具其实用简单的Office和任一个关系型数据库就可以解决,而且根据企业自身的特点,摸索出最适合企业用的工具。

版本控制的最简单方法是在每一个公布的需求文档的版本应该包括一个修正版本的历史情况,即已做变更的内容、变更日期、变更人的姓名以及变更的原因并根据标准约定手工标记软件需求规格说明的每一次修改。

一、版本控制业务流程

利用WebLogicWorkshop的版本控制功能,能够在不中断当前正在运行的任何流程实例的情况下对业务流程进行更改。对业务流程进行版本控制时,便是创建了业务流程的子版本,该版本与其父版本共享同一公共URI(接口)。运行时,标记为有效的流程版本便是将由外部客户端通过公共URI来访问的流程。

注意:可以对业务流程进行版本控制,但无法对与该流程关联的单个控件或其他与业务流程有关的组件(如schema和转换)进行版本控制。对业务流程进行版本控制时,还必须对该流程的子流程进行版本控制,因为对父流程进行版本控制时,该控制对其子流程无效。

二、版本控制中的关键术语

签入文件或目录

此操作将工作目录作为新版本复制回存储库。

签出文件或目录

此操作从存储库中将文件的最新修订版本复制到工作空间。签出目录时,将签出该目录下的所有文件和子目录。

提交文件或目录

此操作与签入文件或目录相同。版本控制用户会经常说他们“已提交更改”;这表示他们对各自文件的工作副本做了更改,并将这些更改提交到存储库。

冲突

当两名开发人员对同一文件的工作副本进行更改,并将这些更改提交到存储库时,他们的工作可能会发生冲突。在这种情况下,CVS或Subversion将检测冲突,并要求某个人先解决该冲突,然后再提交他们的更改。

合并

将对相同文件的不同工作副本进行的多个更改合并到源存储库中。合并是一种管理冲突的策略,它允许多名开发人员同时工作(不必对文件进行锁定),然后将他们的工作并入一个组合版本中。

当对同一文件的不同行进行两组更改时,合并这两组更改很容易,而合并操作也可正常进行。但对文件的同一行或几行进行更改时,将发生冲突,这就要求有人手动编辑该文件,然后才能将这些更改成功提交到源存储库。

存储库

具有受版本控制的所有文件的完整修订历史的共享数据库。

解决

当两名开发人员试图提交发生冲突的更改,而造成文件内的冲突时,必须通过手动编辑该文件进行处理。必须有人逐行检查该文件,以接受一组更改并删除另一组更改。除非冲突解决,否则存在冲突的文件无法成功提交到源存储库中。

修订版本

对各个文件进行具体更新的编号草案。每次编辑文件并将它提交回存储库时,该文件的修订版本号将会增加。

版本

用于标识文件集的编号方案,可在某个时间点标记并命名这些文件集。

工作空间

要在本地硬盘或Unix用户帐户上编辑的文件副本。在工作空间中编辑文件时,这些文件将不再与存储库同步。这就是进度!然后您需要将更改返回存储库,以便其他人可以看到这些更改。

Subversion词汇表

APR

Subversio置于称为APR(Apache 可移植运行库)的可移植层上。这意味着Subversion应该在任何运行Apache httpd的操作系统上工作:Windows、Linux、BSD 的所有 flavors、Mac OS X、Netware 以及其它操作系统。

分支

分支是指目录和文件的现有原始树的副本。分支的生命周期是从某事物的副本开始的,并从此副本处移动,生成自己的历史。通常创建分支以尝试新功能,同时不影响具有编译器错误和小问题的开发的主分支。

检出

检查存储库,会在本地计算机上创建所需分支的副本。此副本包含了您指定的存储库的最新版本。

提交

文件的提交意味着已将对本地副本所做的更改更新到存储库中。提交文件后,用户可以查看对特定文件执行“更新”后的最新版本。

冲突

有时候,当您更新存储库中的文件时,可能会遇到冲突。当两个或多个用户更改文件中的一些相同行时,将发生冲突。

Hook

Hook是被存储库事件触发的程序,例如创建新版本或修改无版本属性。Hook中保留了足够的信息,可以告知该事件是什么、正被操作的目标是什么,以及触发此事件的人员的用户名是什么。

锁定

锁定是指一种机制,在此机制下,用户请求获得修改工作副本文件的更改的专有权限。

合并

合并是指将某分支上的更改联接到此主干或同为主干的另一个分支。

存储库

Subversion的核心为存储库。它是一个存储和共享数据的集中式系统。存储库以一组树和分支的形式(即目录和文件的层次结构)存储信息。任何数量的客户端都可以连接到存储库中,并对这些文件进行读取和写入。

存储库浏览器

在某些情况下中,可能需要直接在存储库中工作而不使用工作副本。这便是存储库浏览器的由来。它与资源管理器窗口具有同样的图标以及用于键入将显示的存储库URL名称的地址栏。它还具有诸如复制、移动和删除等的命令。

存储库URL

可以通过本地磁盘上的不同方法或通过网络协议访问存储库。存储库位置通常指URL。这些URL使用标准的语法,其中引用要指定的服务器名称和端口号

撤消

如果检查时决定取消对文件所做的更改,可以使用“撤消”命令跳转回先前的更改。

修订版本

每次存储库接受提交时,都将创建文件系统树的新版本,称为修订版本。会为每个修订版本分配唯一号,此号比上一修订版本的号大。刚创建的存储库的初始修订版本编号为零,且其中除了空的根目录外不包含任何信息。

修订图形

修订图形是主干位置的图形化表示,其中分支与标记与主干是分离的。这与树结构非常相似,且很容易查看这类信息。

修订版本号

创建新存储库时,其生命周期从修订版本号零开始,且每次后续提交会将修订版本号增加一。提交后,Subversion客户端将提供新的修订版本号。每个修订版本号都会在下方挂起一棵树,每棵树都是存储库对待每次提交的方式快照。

转换

此子命令将更新工作副本以镜像新的URL;通常是共享工作副本中的公共祖先的URL。这是将工作副本移动到新分支上的Subversion方法。

标记

标记主要指在每个文件上置入一个标签,无论此文件的修订版本号。这既可以在工作副本上执行,也可以在存储库自身执行;其效果相同。

更新

更新可以使工作副本与用户对存储库所做的最新更改同步。它会取出文件的最新工作副本置于本地驱动器上。遵照滑块规则,总是在更改文件前更新此文件。

工作副本

工作副本是指从存储库获取的文件的现有副本和已更新副本。若要获得工作副本文件,需要执行检出。

复制-修改-合并开发周期

由于CVS和Subversion都是功能强大的工具,所以学习过程可能会让人望而却步。大量的书籍和网站提供全面的CVS知识库,但提供Subversion知识库的并不多。但是,不是非得学会了整本书才能在软件开发实践中迅速有效地使用CVS或 Subversion。

在与项目的整体开发周期保持一致的情况下,CVS和Subversion都允许您进行自己的开发。

1、要开始项目工作之前,您需要签出源代码。您可以签出该项目的整个CVS或Subversion存储库,也可以只签出您希望处理的那些模块。

2、通过修改这些文件和创建新文件,为项目作出贡献。

周期的这一部分并不直接涉及CVS或Subversion。您可在本地计算机上使用文件编辑器修改项目文件的工作副本。还可以保存并编译您编辑过的文件,以测试您所做的更改如何影响正在处理的特定项目模块,此过程不影响其他人对同一项目文件的工作。您所执行的任何操作都不影响其他项目参与者,除非您将更改合并到项目存储库中。

3、您在自己的工作空间中测试和调整您最新的更改,以确保这些工作不中断或损坏整个项目。

4、最后,将您所做的更改返回或签入项目文件的主要或“顶级”主体,将您的工作合并到最近的工作版本(在版本控制术语表中称为head)。

提交您的更改以与其他开发人员的工作合并是CVS和Subversion最强大的功能,但此功能也使它成为最危险的方面。有时可能因为一时糊涂,无意中复盖了他人或您自己的更改。您所提交的更改将始终在某些方面与其他人的更改相冲突。在合作开发项目中,理解?冲突是使用CVS或Subversion时两个特别关键的方面。

所有起作用的开发人员在项目生命周期中都在不断重复着这个复制-修改-合并周期.CVS和Subversion使得每个人都能同时处理项目文件,掌握其他人进行的最新更改,以及测试自己的更改如何影响整个项目,这些过程都不会中断其他开发人员的周期。

三、版本控制的选择

在八月份的时候,一些读者写信要求我说明如何控制接口的版本。实作新版接口时,有些情况你只需要强化现有类别,在其它情况你则需要实作一个可能使用前版的新类别。我想要提出的是相信大部分读者都会遇到的组合情况,这里列出当您在更新Web服务时最常面临到的工作:

1.新增额外的方法。新方法在概念上和现有的Web服务是相关连的,而且应该在相同的端点上实作。

2.变更方法签名码。在这个实例中,输入组件的数目和类型会改变。

3.更新数据模型。在这个实例中,资料型别会扩充且资料成员可能会改变名称。

为了准备场景,我想要规划一个简单的Web服务,让它能够接受所有类型的改变,这个Web服务代表版本1。类别和这个Web服务会对应一个命名空间同步进行。所有动作都会随着这篇文章逐步发展。

版本1

我要为稍后会作的修改提供一个起点。每一个区段都建置在这个初始Web服务之上,然而下面的区段却是建立在彼此的Web服务上。这个服务是设定用来处理讯息,以便将两个数字加起来,以及将一些基本个人资料转换成字符串。

【WebServiceAttribute(Namespace=NamespaceConsts.AYS15Oct2002)】

publicclassVersionOne:System.Web.Services.WebService

【WebMethodAttribute】

publicstringGetDisplayValue(Personperson)

returnperson.ToString();

【WebMethodAttribute】

publicintAdd(inta,intb)

returna+b;

命名空间字符串会储存在一个位置中,即NamspaceConsts类别,来减少由于打字错误产生的问题。我会大量重复使用这个命名空间值,来减少输入错误字符串的机会。

publicclassNamespaceConsts

这个内容值包含用于XML命名空间的字符串

http:msdn.microsoft.comsamplesAYS20021015

publicconststringAYS15Oct2002=

"http:msdn.microsoft.comsamplesAYS20021015";

这个内容值包含用于XML命名空间的字符串

http:msdn.microsoft.comsamplesAYS20021022

publicconststringAYS22Oct2002=

"http:msdn.microsoft.comsamplesAYS20021022";

最后,第一版的Web服务采用了一些其它类别:

·PersonName:这个类别包含三个字符串成员变量分别纪录一个人的名字、中间名和姓氏。

·USAddress:这个类别包含其它成员变量代表街道地址、城市、州和邮政编码。

·Person:这个类别包含两个公用成员,PersonName和USAddress。

所有的类别都使用System.Xml.Serialization.XmlTypeAttribute来确定当类别序列化成XML时,这些类别是使用相同的XML命名空间。在这里以Person类别为例子。

【XmlTypeAttribute(Namespace=NamespaceConsts.AYS15Oct2002)】

publicclassPerson

publicPersonNameName;

publicUSAddressAddress;

publicoverridestringToString()

returnstring.Format("0n1",

Name.ToString(),

Address.ToString();

这里非常详细的说明这个Web服务版本1的内容。

增加额外的讯息

【WebServiceAttribute(Namespace=NamespaceConsts.AYS15Oct2002)】

publicclassVersion2a:System.Web.Services.WebService

【WebMethodAttribute】

publicstringGetDisplayValue(Personperson)

returnperson.ToString();

【WebMethodAttribute】

publicintAdd(inta,intb)

returna+b;

【WebMethodAttribute】

publicintSubtract(inta,intb)

returna-b;

【WebServiceAttribute(Namespace=NamespaceConsts.AYS22Oct2002)】

publicclassVersion2a:System.Web.Services.WebService

【WebMethodAttribute】

【SoapDocumentMethodAttribute(

NamespaceConsts.AYS15Oct2002+"GetDisplayValue",

RequestNamespace=NamespaceConsts.AYS15Oct2002,

ResponseNamespace=NamespaceConsts.AYS15Oct2002)】

publicstringGetDisplayValue(Personperson)

returnperson.ToString();

【WebMethodAttribute】

【SoapDocumentMethodAttribute(

NamespaceConsts.AYS15Oct2002+"Add",

RequestNamespace=NamespaceConsts.AYS15Oct2002,

ResponseNamespace=NamespaceConsts.AYS15Oct2002)】

publicintAdd(inta,intb)

returna+b;

【WebMethodAttribute】

【SoapDocumentMethodAttribute(

NamespaceConsts.AYS22Oct2002+"Subtract",

RequestNamespace=NamespaceConsts.AYS22Oct2002,

ResponseNamespace=NamespaceConsts.AYS22Oct2002)】

publicintSubtract(inta,intb)

returna-b;

因为我们选择建立这个Web服务的方式的不同,现有的属性方法,亦即允许开发人员指定特定的作业所属的系结,在这个情况是没有作用的。Add和GetDisplayValue的讯息并不会因为任何方法而改变,意味着我不能只是「正确地」设定属性然后就继续进行。关于这点,您有两个选择:

1.撰写一些额外的程序代码而且放弃在一个端点上支持两个版本。

2.将这两个版本的系结信息储存在各自的档案、并为这个端点撰写一个自订的WSDL档案,然后关闭这个Web应用程序文件。

让我们依序来看这两种选择。

撰写额外的程序代码

【WebServiceAttribute(Namespace=NamespaceConsts.AYS22Oct2002)】

publicclassVersion2b:WebService

【WebMethodAttribute】

publicstringGetDisplayValue(Personperson)

呼叫原始函式

VersionOnev1=newVersionOne();

returnv1.GetDisplayValue(person);

【WebMethodAttribute】

publicintAdd(inta,intb)

呼叫原始函式

VersionOnev1=newVersionOne();

re

turnv1.Add(a,b);

【WebMethodAttribute】

publicintSubtract(inta,intb)

returna-b;

如您所见,对Add和GetDisplayValue的呼叫会委派原来版本的要求。

自订的WSDL

目前我能确知的是,不可能找到方法让ASP.NET自动产生正确的WSDL。这里是我们接下来的步骤:

1.储存VersionOne.asmxWeb服务的WSDL。

2.储存Version2a.asmxWeb服务的WSDL。

3.从WSDL文件中移除服务元素。

4.将版本1命名空间的结构描述(Schema)放进各自的XSD档案。

5.撰写并储存Version2a.asmxWeb服务的WSDL档案。

6.将文件关闭。

namespace="http:msdn.microsoft.comsamplesAYS20021015"

location="http:localhostAYS15Oct2002MessageTypes.xsd">

这个Web服务的新WSDL是:

xmlns:s1="http:msdn.microsoft.comsamplesAYS20021022"

xmlns:soap="http:schemas.xmlsoap.orgwsdlsoap"

xmlns:s0="http:msdn.microsoft.comsamplesAYS20021015"

targetNamespace="http:msdn.microsoft.comsamplesAYS200210Impl"

xmlns="http:schemas.xmlsoap.orgwsdl">

location="http:localhostAYS15Oct2002VersionOne.WSDL">

location="http:localhostAYS15Oct2002Version2a.WSDL">

location="http:localhostAYS15Oct2002Version2a.asmx">

location="http:localhostAYS15Oct2002Version2a.asmx">

注意到这两个连接端口的位置是相同的。最后关闭这个文件。要做到这点,必须在web.config中的configurationsystem.webwebServicesprotocols区段加入下面几行:

那么这个选择完成了什么事情?我们修改了WSDL,让它准确反映两个Web服务版本都接受的讯息。建立的新WSDL显示这个端点了解两份文件中所定义的讯息。这个基础Web服务因其编码方式而能够接受两种版本的讯息。

增加新方法不是开发Web服务的唯一方式。接下来,让我们来看假使您想变更方法签名码时,要如何处理。

变更方法签名码

在这个例子中,我假设您想要让现有版本仍然能够运作,而且您想要改变特定讯息的内容。让我们来看看改变Add讯息以接受一个整数数组,然后传回这些整数的总和。这个新的Add讯息和旧的是不兼容的。

我可以赋予这两个讯息不同的名称使它们都在同一个端点操作,但这不是我想要做的。这个WSDL需要反映出这个方法是较新且较佳的Add的形式。为了让这项分别更清楚,并与其它函式一起运作,我建立一个新的Web服务叫做版本2c。我也决定将GetDisplayValue移到新的XML命名空间。这个函式还是呼叫内部的GetDisplayValue方法来利用现有的程序代码和未来的错误修正。

【WebServiceAttribute(Namespace=NamespaceConsts.AYS22Oct2002)】

【WebServiceBinding("Version2",NamespaceConsts.AYS22Oct2002)】

publicclassVersion2c:System.Web.Services.WebService

【WebMethodAttribute】

【SoapDocumentMethodAttribute(Binding="Version2")】

publicstringGetDisplayValue(Personperson)

VersionOnev1=newVersionOne();

returnv1.GetDisplayValue(person);

相关词条

相关搜索

其它词条