SVN,一个版本控制系统,用于团队协作开发。

版本控制:

标记不同的版本需要使用编号,SVN使用Revision来作为版本编号。
Revision是一个随着提交递增且唯一的自然数,每次新的提交Revision都会加一。
Revision应用于整个仓库,不只在单个文件上生效。(修改了仓库中一个文件,提交之后其实整个仓库Revision都增加了,每个Revision可以理解为整个仓库在某次提交之后的快照。)

协作:

协作开发需要关注问题就是多人修改同一个文件时如何保证修改正确的合并起来。File Sharing和Lock-Modify-Unlock模式都有各自的缺陷,SVN使用的Copy-Modify-Merge模式很好的解决了这个问题,如下是对三种模式的介绍。

File Sharing,会有操作覆盖的问题。

Lock-Modify-Unlock,同时只能有一个人在读写,影响协作效率。

Copy-Modify-Merge,SVN采用的模式,不会有覆盖的问题,且不影响相互的工作进度。

版本管理

SVN常用于代码版本管理,常用的版本管理模型分为两种。

主线开发模型:

  1. 在trunk上进行版本开发
  2. 版本完成开发并测试通过,准备发布,从trunk copy 一个release分支出来进行发布。
  3. 新版本继续在trunk上进行开发,重复步骤1和2
  4. 如果有一些特殊的功能模块需要独立开发(比如可能无法和版本一起上线),从trunk上copy Feature Branch进行开发,完成开发后merge 回 trunk 进行发布。

使用场景:维护人员较少,定期发布,团队成员一般都是一起做一个版本的功能,且同时发布。

release主线,功能分支开发模型

  1. 主线为release版本,用作发布
  2. 有新版本或新功能,从release中copy一个feature branch来,进行开发,开发完成之后merge 回release分支进行发布。

使用场景:维护人员多,发布频繁,无固定发布周期,多功能分支。

合并

上述两种方案都涉及到两种合并:

  • feature merge 回主线。
  • feature 定期和主线代码同步,将主线代码merge到feature中。
    • SVN建议尽量避免该种情况,因为merge起来冲突会比较多。实在有必要,建议只定期merge有价值的改动
    • 完成同步操作,将主线merge到feature上和从主线copy一个分支将feature merge上去,两种做法本质上没有区别,后者并不会避免冲突的发生,同时后者还多操作。
分支

SVN中拷贝分支的并不是把分支数据完全复制一遍,SVN只是把创建了一份链接(link到对应的文件),只有在需要区分文件版本的时候才会copy一份数据,然后修改下对应的link。
所以SVN的copy成本并不高,照官方的说法是“Cheap Copies”。

冲突:

因为是协作开发,所以会有各种分支,在分支合并时肯定会有冲突,SVN中将冲突分为两种。

  • text conflicts:两个人同时修改了相同文件,且修改无法很清楚的merge(修改了同一行,但是修改不同),会报该问题。
  • tree conflicts:目录层面的conflicts。本地修改了一个别人删除的文件,在更新merge时会报该问题。其他可以归为目录conflicts的操作都会报该问题。

特殊情况举例

除了上述提到的,feature可能需要和主分支保持定期同步,同时还可能需要和别的feature保持同步,我们在以release为主线的情况下举例该情况,并支持一些错误的操作方案以及正确的操作方案,有助于加深对Revision和conflicts的理解。

场景
  1. release作为稳定主线版本。
  2. feature-1从release copy出来进行开发。
  3. feature-2从release copy出来进行开发。
  4. feature-2在开发期间需要使用feature-1的新功能,且在feature-1上线前就要使用(feature-1 在 feature-2前上线),所以需要把feature-1 同步到feature-2上。

错误操作
  1. feature-1 merge到了feature-2中。
  2. feature-1 继续后续开发,开发完成后 merge 回release,发布release。
  3. feature-2 开发完成后,merge回release时,在feature-1中新增的文件(feature-2中未修改)产生了tree conflict。

产生conflict原因分析:feature-1 merge进feature-2后,相当于feature-1的改动在feature-2上实现了一遍,会生成一个新的Revision = X;然后将feature-1 merge进release,feature-1的改动会在release上生成一个新的Revision = Y(X != Y,两者除了Y比X大其他没有任何关系,可以理解为两次单独的修改);后续feature-2 merge 到 release时,对于在feature-1中新增的文件,相当于在两个不同的Revision中,该文件都被新建,所以产生了tree conflicts。

正确操作
  1. 从release中copy出feature-3
  2. 将feature-1 merge 到feature-3
  3. 从feature-3 中copy出 feature-4 来进行feature-1 的后续开发,完成开发后merge回release。
  4. 将feature-2 merge到 feature-3中,在feature-3中继续feature-2的开发。

核心理念

不要把feature merge到两个分支中,同时这两个分支后续还需要进行merge,这样会出现冲突。因为相当于两个分支上各自进行了feature的开发,两者并无关联关系,虽然merge来源一致。