启用SVN的分支管理

来源:互联网 发布:免费域名有哪些 编辑:程序博客网 时间:2024/05/03 23:02

前提

使用SVN分支技术,需要理解并掌握SVN的基本操作。

如果对SVN的基本操作不熟悉,或者存在理解上的问题,可能对分支的使用造成障碍。

 

一些基本概念:

1.版本库

版本库就是SVN服务器上,存放记录了文件、目录每一次变化的数据库。

 

2.工作副本

工作副本(也叫工作拷贝,很多时候简写做WC——即Work Copy)。它是版本库代码在本地的映射,开发人员在本地的工作副本中做修改再上传到SVN版本库中。

 

开发人员对于同一个版本库路径,比如https://KFBServer/svn/xykj_2013/trunk,可以创建无数个不同名称的本地文件夹进行下载,这就是“副本”这个名称的意义。

 

3.TTB目录

trunk、tags、branches

trunk:存放开发主线的文件夹,用于创建分支、合并分支、创建标记。

branches:存放分支的文件夹。

tags:存放“快照”的文件夹。通常,tags目录中的东西不再允许修改了,作为一个“定版”来测试、发布。简单的说,一个标签就是具有特定意义的一个版本。 

“分支(branch)和标记(tag)对于 SVN 来说其实都只是主干的拷贝,这些拷贝本身并不存在分支和标记的区别,分支和标记的意义是我们人为给予的”。这句话在分支的使用中就会慢慢理解。

 

4.廉价拷贝

对于SVN来说,通常意义的创建分支,只不过是在版本库内创建了一个目录,并复制了一些文件和子目录过去。但你不需要担心版本库的体积会变得十分巨大,因为Subversion并不是拷贝真实的文件,而是通过拷贝“文件的快捷方式”来完成的。只有当复制后的目录、文件被程序员在本地做了修改并提交到版本库时,SVN才会用真实的文件来存储它们。

 

基本概念

一、什么是分支。

分支是软件开发中源代码管理的一种技术,而不是产品版本——比如精简版、普通版、豪华版,也决不是针对特定用户的特殊修改。

所谓的分支就是一条开发线。

 

说明:上图仅仅描述了分支的创建,并未谈到分支的合并。

不合并的分支只会得到不同的产物,这与我们的初衷相违背,因此我们在使用分支的时候,一旦分支代码通过了测试就必须合并,这样才能形成统一的一套代码。

 

二、为什么要使用分支

分支的作用:隔离。

1.避免未经测试的修改提交到版本库后对编译出的产品造成影响。

2.允许多个开发人员同时修改某一产品的代码时互不影响。

3.允许开发人员在自己的分支中提交半成品代码,即使是无法编译的代码;

4.单个开发人员通过创建多个分支,从而可以同时修改多个问题,并随意切换。相反,在单一开发线中修改多个问题,就很麻烦。

5.允许新入职员工随意修改代码。

 

三、分支和文件系统中简单的拷贝有什么不同

文件系统的拷贝:未处于SVN的管理中,人工比较、跟踪其他分支线的变化非常痛苦,而且容易造成闭门造车的结果,导致合并困难。

分支:处于SVN的管理中,大大减少了人工比较、跟踪其他开发线的工作量。分支既保持独立,又可以随时共享。

 

具体操作

使用分支前需要对版本库做结构调整,目前调整后的结构如下(不排除在对SVN更加了解以后会进行调整):

权限设置如下:

trunk:仅管理员可修改(用于新建项目),下面各文件夹的内容开发人员可读写(因为需要从分支做合并操作)。

tags:仅部门经理可写(用于创建特定版本,比如用于发布、通测等),其他用户只能读。

branches:管理员和部门经理可读写(用于清理很久不合并、不删除的分支),每个开发人员有一个固定的目录,只能读写自己的分支目录,看不到别人的目录。

 

假设场景:需要修改缺陷管理平台上的#77问题,那么首先从主干创建分支。

 

创建主干的分支

 

创建分支有多种操作方法。

1.使用本地工作副本的主干上创建分支。

在本地工作副本的主干目录(trunk)上,右键点击然后选择“分支/标记…”

 

在弹出的窗口中,默认的新分支的目标URL将会是主干trunk的URL。你需要把这个URL修改为新分支的路径。

将“至路径”指向branches目录并输入分支的具体目录名,这里是“问题077”,我们即将创建的分支便存放于此处,点击确定。

 

建议:分支目录名遵循一定的规则,比如使用缺陷管理平台的问题号,或者写明问题名称,这样便于查询这个分支是为解决什么问题而建立的。而且最好是一个问题一个分支。

 

现在你需要选择从哪里复制。你有三个选择: 

1.版本库中的最新版本:新的分支从trunk的最新版本复制到版本库中。

注意:此时,数据的拷贝发生在服务器上版本库的内部,而不是从你的工作副本发送到版本库的branches目录下,因此创建分支会非常迅速。

☆讲完分支再讲标签☆

2.版本库中指定的版本新的分支从你选择的trunk的历史版本复制到指定的分支目录

这个功能主要用来创建标签。关于什么是标签,后面会讲到。比如:当你上一周发布了一个产品出去,但忘记了创建标记,这就很有用了。

如果你不记得版本号,可以点击右边的按钮来显示版本日志,然后从中选择版本号。这种方式需要从你的工作副本传送数据到版本库,分支非常迅速的被创建。

☆最后来讲切换☆
3.工作副本通过上传你的本地工作副本来创建新的分支

这个方法非常的特殊,它允许你制造出非常复杂的分支!而不是项目的某个修订版本中所有文件、目录的完整副本。

假设某个项目保存了一组子目录和许多文件,你可以通过选择性的回滚某些文件和目录到特定修订版本,或者切换某些文件和目录到特定分支,甚至你可以做各种本地修改。

这样,你的本地拷贝就变成了一个包括特定特性和Bug修正的工作副本,形成了你所需要的一种精确数据组合。然后,你可以使用这个本地拷贝来生成分支。

当然,如果你的本地修改不存在于版本库中,这些变动就会从你的工作副本传输版本库,而那些回滚或切换的历史版本的文件、目录,SVN会在分支目录中做快捷链接。

 

创建临时文件夹:这个功能的意义是如果你所输入的路径在SVN版本库中不存在,那么SVN会帮你创建所需要的目录。

比如你输入的分支路径是/branches/罗乐/为融资将/德润/…/问题99,因为“为融资将/德润/…/”这些目录事先没有建立,勾选此项后,SVN会帮你创建这些中间目录。

 

☆最后来讲切换☆

切换工作副本至新分支/标记:(不选)

这里需要讲一下什么叫切换。如果你拥有同一个项目的多个分支,比如BranchA、BranchB,他们都包含了很多相同的文件和目录,差异仅仅是几个文件有所不同。那么实际上,你不必同时拥有BranchA、BranchB的本地拷贝,你可以先取出BranchA的代码到本地目录AB中,修改后提交,当你需要修改BranchB中的文件时,在本地目录AB上使用“切换”,就可以只下载BranchB中不同于BranchA的那几个文件到本地,从而使得本地目录AB中存放的是BranchB的代码,就可以进行BranchB分支的修改工作了。

需要注意的是:如果目录AB中原来存放的是BranchA的代码,你做了本地修改没有提交到BranchA中就进行了切换,那这些本地修改会被合并到BranchB的代码中。

 

仍然回到选项本身,如果想要将当前的工作副本(也就是选中的trunk)自动切换到新创建分支,那么就选中切换工作副本至新分支/标记复选框。这样一来,svn会下载代码,使得你的本地trunk目录中保存的就是新创建分支的代码。

还是那句老话,如果你要这样做,首先确认你的本地trunk工作副本中不包含修改。如果存在修改,这些修改将会在你切换时合并到分支的工作副本中。

我本人不喜欢使用切换,因为这可能造成混淆。如果你的记忆力非常强、思路非常清晰,那么你可以使用切换。

 

 

其实除了可以在本地拷贝上右键创建分支,还有几种不需要本地拷贝就可以创建分支的方法:

1. 打开版本库浏览器。按下 Ctrl 键并拖动你要创建分支的项目的文件夹到branches/xxx目录下从而创建副本。

 注意:你必须在拖拽过程中按下 Ctrl 键,否则文件夹是被移动,而不是被复制。

2.你可以使用鼠标右键拖拽某个项目文件夹。

 当松开鼠标右键时会出现菜单,让你选择移动还是复制文件夹。

☆讲完分支再讲标签☆

3.从日志对话框中创建分支,这个功能通常用于创建历史版本的标签,比如某个历史版本需要做标签,但你忘了做。

具体操作:你可以对本地拷贝,或者在“浏览版本库”中,对某个文件夹做“显示日志”的操作,在日志对话框,选择一个版本(可以是位于顶端的最新版本,也可以是先前的版本),右键单击并选择从版本创建分支/标记。

 

推荐在版本库中做分支操作,这样你可以多次拖动你本次修改需要用到的项目文件夹到分支目录中,从而减小分支在本地拷贝的体积。
但需要注意的是,以后在做合并操作时,源、目的url都必须是子目录或具体的文件,否则未拖动过来的根目录的文件、目录就视为被删除了,一旦提交,就导致主干trunk中的这些文件、目录被删掉。

比如

 

 

 

取出分支开始修改

 

分支建立之后,就可以取出分支的代码进行修改工作了。

取出分支的操作很简单,到branches目录下做“svn更新”即可。

实际上,你并不一定要在本地拷贝下的branches目录下做更新,你可以在本地硬盘上的任何目录下做分支url的更新,取出的都是版本库上新创建的分支的代码,之所以放在本地branches目录下,是为了便于管理。

 

另外说一下,目前的SVN版本库规划是不同开发部门的所有项目都在一个版本库中,导致每次在根目录做更新时,就会下载到其他部门的不相干的代码。实际上,可以通过权限控制使每个部门只下载自己的代码,以及需要共享的代码,从而减小本地拷贝的大小。

 

这里讲一下“切换”。切换是在本地拷贝上执行的操作,假设你同时拥有多个分支,分支A、分支B,在项目顶级目录上执行切换动作,可以下载特定的分支的本地拷贝,而且切换动作只会下载并覆盖存在差异的文件,从而减少网络传输。

 

合并分支

 

合并操作非常灵活,可能存在以下情形需要用到分支:

1.当你某个分支修改完毕并通过测试的时候,你就需要合并到主干上;

2.你同时拥有分支A、分支B,你发现分支A中存在一个BUG,然后你解决了这个BUG,此时你并不打算立即把AB合并到主干上去,那么你可以把这种修改合并到分支B去,以免以后合并分支B到主干的时候忘记这里为什么存在差异。

3.你正在修改某个分支,发现主干代码发生了变化(你可以在修改分支时,随时更新主干),那么你需要把主干的这种变化合并到分支中,以免分支和主干越来越远。

合并和创建分支不同,创建分支可以不需要工作副本,直接在版本库中操作,但合并必须在本地工作副本中进行操作,合并成功后用户检查代码的正确性,再提交到版本库上。所以你必须取出合并操作的源和目的开发线的代码到本地来操作。

另外,在合并操作之前,应该确保:

①源开发线中的修改都已经提交到版本库中了,这样源开发线的工作不会遗漏;

②目标开发线中不存在本地修改!因为合并操作发生在本地,如果目标开发线中存在本地修改,这些修改可能被丢失,另外也增加了合并操作的复杂性。 

点击右键之后,会出现如下的对话框,提供了两种合并方法。这些合并方法其实都差不多,仅存在细微的差别,

 

1.合并一个版本范围

如果你在某个开发线上(分支或主干)上做了多次修订(即多次修改并提交),使用这个方法就可以把“某个开发线上从修订版本n到修订版本m的修改”应用到其他的开发线。

意义在于:让你可以选择不同开发线上特定的修改进行合并,因此,你可以继续在分支上进行开发,而只合并分支上的某一部分历史修改(这通常意味着在该分支上修改了多个问题,不推荐这样做)

Subversion 会做如下事情: “计算[从]开发线 A 的版本 n [到] 版本 m 所需的修改,并将这些改变应用到开发线B(主干或分支)的工作副本上。”

 

2.合并两个不同的树

此合并方法的意义我并不是很理解,按照我自己的推测:它比较的是两个开发线的整体差异,并进行合并。

比较通用的用法是:当你完成某个分支的所有修改之后,你希望将这个分支的修改合并到主干上,就是用此方法,此时,Subversion会做的动作是:“计算[从]主干的某个版本变化[到]分支的某个版本所需要做的修改,并将这些修改应用到(主干的)工作副本。”最终,主干与分支一模一样。

注意:在这种情况下,你需要从一个主干的工作副本内启动合并向导。

 

标签

其实分支和标签没有区别,创建分支和创建标签都使用相同的技术——拷贝,仅仅是因为SVN管理员在标签tags目录上的权限控制更加严格,导致只有特定的用户(比如部门经理)可以做写入操作,而大多数用户只能读取而已。

(回到前面,讲标签)

建立简单标签

 

建立复杂标签

 

 

分支管理:常用的分支模式

 

一.特性分支

特性分支是一个临时分支,用来增加新特性、bug修正等操作,而不会干扰/trunk的稳定性,特性分支诞生后,使用了一段时间,合并到主干,最终被删除。 

 

二.发布分支

大多数软件存在这样一个生命周期:编码、测试、发布,然后重复。

这样有两个问题:

第一,当某个假定稳定版本(比如1.0α)出炉时,测试组需要对其进行测试,而开发者需要继续为下一个大规划版本(比如2.0版本)开发新特性,新增特性等开发工作在测试1.0α时不可以中断;

第二,对于历史发布版本(比如1.0版本)中的bug,客户希望立刻得到修正而不必等到下一个大规划版本(比如2.0)的发布才得以解决;如果一个bug在最新的代码中发现,它一定也存在已发布的版本中。

 

要解决这些问题,可以使用SVN的发布分支来实现,具体过程如下:

·不论是直接修改trunk还是通过特性分支的方式,开发者提交所有的新特性、bug修正等到主干。

·当版本管理团队认为软件已经做好发布的准备(如,版本1.0),主干trunk代码被拷贝到“测试”分支,比如/test/1.0。测试小组开始对 /test/1.0 进行测试,开发小组在主干/trunk继续为实现 2.0 版本继续新的工作。

·此时进入1.0和2.0的并行工作阶段。如果一个bug在 /test/1.0 被发现,那么这个错误需要在 /test/1.0 和 /trunk上同时被修正。如果 /trunk 中发现了一个bug,通常也需要在 /test/1.0 同时做修改,但如果版本管理团队认为 /test/1.0已经完成了最终测试,那么此bug可以不纳入 /test/1.0 中。

·当 /test/1.0 完成最终测试后(可能还有一些bug,但不打算在1.0中解决了),就可以拷贝到 /tags/1.0 目录下作为1.0版本发布。

·当继续在/trunk上为版本2.0工作,bug修正继续从/trunk运送到/branches/1.0,如果积累了足够的bug修正但版本2.0的规划尚未达成,管理部门则决定发布1.0.1版本,拷贝/test/1.0(注意:这个/test/1.0的代码是处于不断变化中的)到/tags/1.0.1,1.0.1版本被打包发布。

·整个过程随着软件的成熟不断重复:当2.0完成,一个新的2.0分支被创建,测试、打标签和最终发布。

 

 

另外,使用特性分支的策略也是多种多样:

一些项目永远不使用特性分支:大家都可以提交到/trunk,好处是系统简单——没有人需要知道分支和合并,坏处是主干会经常不稳定或者不可用;

一些项目使用分支达到极限:任何修改都不能直接提交到主干,即使最细小的修改都要创建短暂的分支,然后小心的审核合并到主干,然后删除分支,相对方式繁琐一些,但保持了主干一直稳定和可用。

 

许多项目采用折中的方式,坚持每次编译/trunk并进行回归测试,只有需要多次不稳定提交时才需要一个特性分支,这个规则可以用这样一个问题检验:如果开发者在好几天里独立工作,一次提交大量修改(这样/trunk就不会不稳定。),是否会有太多的修改要来回顾?如果答案是“是”,这些修改应该在特性分支上进行,因为开发者增量的提交修改,你可以容易的回头检查。

最终,有一个问题就是怎样保持一个特性分支“同步”于工作中的主干,在前面提到过,在一个分支上工作数周或几个月是很有风险的,主干的修改也许会持续涌入,因为这一点,两条线的开发会区别巨大,合并分支回到主干会成为一个噩梦。

这种情况最好通过有规律的将主干合并到分支来避免,制定这样一个政策:每周将上周的修改合并到分支,注意这样做时需要小心,需要手工记录合并的过程,以避免重复的合并(在“手工跟踪合并”一节描述过),你需要小心的撰写合并的日志信息,精确的描述合并包括的范围(在“合并分支到另一分支”一节中描述过),这看起来像是胁迫,可是实际上是容易做到的。

0 0
原创粉丝点击