zoukankan      html  css  js  c++  java
  • SVN并行开发管理策略

    总的原则:trunk保证相对稳定。分支合并到主干时将冲突降至最低。

    (1)       trunk用于集成、测试、发布,可以提交fixbug代码,但不允许直接提交新特性。

    (2)       特性在分支上开发,在编译、测试通过后才能合并到主干。

    (3)       特性分支确定一个负责人,负责每天执行从trunk到分支的合并。合并回trunk前,先执行一次trunk到dev的合并,然后在trunk上使用复兴分支。

    (4)       特性分支的存在时间不能太长,不超过一周为宜。合入主干后不能继续使用。

    相册特性开发-采用特性分支

    特性分支: 为了使新特性的开发不影响测试或发布,把新特性开发放在分支上进行管理,分支的生命周期取决于特性的开发周期,该策略的特点是:

    1)  trunk用于集成、测试、发布

    2)  新特性放在分支上开发

    3)  分支负责人定期(如每天)把trunk的变更同步至分支

    4)  分支合并回trunk前先执行trunk到分支的合并,然后使用复兴分支

    5)  分支合并回trunk后,分支生命周期结束,清理分支。

    第三方代码管理-采用供应商分支

    这里的供应商分支通常是指对第三方源代码的管理,供应商分支的管理通常步骤如下:

    1)  创建供应商分支目录,导入供应商代码,供应商代码的维护在此分支上进行

    2)  将供应商分支拷贝(branch/tag方式)到trunk或开发分支的某个目录下

    3)  trunk或开发分支不对供应商分支代码做修改

    4)  trunk或开发分支确认使用供应商分支的新版本时,把供应商分支合并到trunk或开发分支

    可能会有人存在疑问,为什么要对供应商内容做管理?

    供应商代码和自己的产品代码可以看着是两个产品线,供应商的代码可能随时会发生变化,为了不让供应商代码的变更影响自己产品的正常研发,就有必要使用分支独立管理供应商代码。

    供应商分支还可以被另外一种方案所替代,那就是:外部引用(svn:externals)

    分支合并到主干策略

    如果说到svn使用最痛苦的一点,那莫过于主干合分支,或者分支合主干时爆发的各种莫名其妙的冲突狂潮,如“树冲突”,“文件冲突”,“文件丢失”等等。解决起来费时费力,还容易出错,效率很低。有没有较好的解决方法,可以让日子好过一点呢?答案是有的,需要遵循下面的方法。

    冲突产生的根源

    svn版本管理原理

    svn生成的每个版本只记录增量修改,每个文件都有一个根源版本。

    根源版本


    根源版本,即祖先版本,在合并的时候是比较重要的一个概念,类似于C++中基类和派生类的关系,这里所说的根源就是一个基础版本。

    如上图所示,hello.h的v1版本是v2版本的根源,而v2则是v3、v4的根源。

    当进行分支合并时,SVN会沿着分支和trunk追溯共同的根源版本,然后计算其差异,如果没有共同的根源,则会报树冲突,就只能使用忽略根源的方式进行合并了。

    冲突1:丢失文件及可避免的树冲突(可以避免)

    当多人协作开发时,如果分支间合并缺乏时序性,就有可能导致合并时丢失文件。

    举个简单例子来说:

    如上图所示:

    A和B两人同时在2.0-dev分支上开发,A新增一个a.cpp,并提交到SVN版本库上,产生123版本;然后B基于A提交的a.cpp做修改,提交后生成一个新版本124;

    如果B此时想把自己修改的版本124merge到trunk,那么问题就来了,因为124版本的根源版本是123,只合并124过来,实际上就相当于只合并124的变更内容,而此时trunk上还没有a.cpp,这时SVN就会认为trunk上的a.cpp被删除了(因为找不到),会提示用户一个树冲突;

    【由于是从2.0-dev合并到trunk, trunk是主合并方,分支是从的关系(在SVN中,trunk的东西称着mine,而分支是theirs),所以处理树冲突的时候优先用mine来解决】

    当124合并到trunk时,由于找不到a.cpp,SVN会报一个树冲突,用trunk解决冲突,实际上也就是不会把a.cpp合并过来,这就会导致合并时出现丢失文件的现象。

    冲突2:文本冲突(无法避免)

    当A、B两人同时修改一个文件的同一行时,工具不能判断到底是选择A的修改or选择B的修改,或者是A和B的修改都要,这个事情就会报一个冲突,这种冲突也就是文本冲突。

    冲突3:树冲突 (无法避免)

    当A、B同时改了一个文件,A删除了该文件,而B修改了该文件,这时由于二者的修改无法进行合并,所以只能让用户二选一,要么删除该文件、要么保留该文件,这种冲突是树冲突。

    树冲突产生的场景比较多,以下A和B的任何一种操作组合都会导致树冲突。

     

    推荐的合并实践

    1)  创建分支时,在日志中写明主干当前版本号。

    2)  创建分支后,每天同步一次主干到分支, 并在日志中写明合入的主干当前版本号,便于定位问题。合并命令的用法见小节《常用svn命令》

    每天合并问题最容易定位与解决,这也应了敏捷开发中小步快跑的思想,以及持续集成的初衷都是一样的;如果这个频率不能保证,每周也至少2-3次,否则解决冲突与定位问题的代价就大了。

    3)合并回主干前,先执行一次主干到分支的合并,然后在主干上使用复兴分支。复兴分支使用了合并跟踪技术(svn1.5以上),能够不指定合并版本范围就将分支中的改动自动合入主干。

    4)特性分支的存在时间不能太长,不超过一周为宜。合入主干后不能继续使用,否则当下次从trunk合到此分支时,会引入大量的树冲突。

    svn常见使用流程讲解

    命令行下字符编码的问题:目前相册源程序文件使用的都是gbk编码,而svn提交时默认使用utf8编码。我们希望在终端使用GBK编码,包括编译调试,但是使用svn时切换到utf8编码。所以需要如下两个封装的命令

    命令

    在.bashrc中加入下列两行,并且执行source ~/.bashrc

    alias svncoding="export LC_ALL="en_US.UTF-8""

    alias gcccoding="export LC_ALL="en_US.ISO-8859-1""

    作用

    编码方式切换

    示例

    svncoding切换到svn需要的编码(utf-8)

    gcccoding切换到开发、编译需要的编码(ISO-8859-1编码无法表示编码,但是开发机对应的默认中文显示用gbk。原因何在?开发机/etc/sysconfig/language里写的是RC_LANG="en_US.UTF-8",secureCRT中使用默认设置(windows默认GBK),看来是以终端编码为准)

    结果

    命令

    在.bashrc中加入下列两行,并且执行source ~/.bashrc

    export PHOTO_REPO=

    ” https://tc-svn.tencent.com/isd/isd_qzoneplatformdev_rep/QzonePhoto_proj”

    作用

    代表相册代码svn库地址,便于快捷输入,减少输入量

    示例

    echo $PHOTO_REPO/trunk

    结果

    https://tc-svn.tencent.com/isd/isd_qzoneplatformdev_rep/QzonePhoto_pro/trunk

    命令

    svn info TRUNK_URL

    作用

    获取svn库的最新信息,如trunk的当前版本号

    示例

    svn info $PHOTO_REPO/trunk

    结果

    Path: trunk

    URL: https://tc-svn.tencent.com/isd/isd_qzoneplatformdev_rep/QzonePhoto_proj/trunk

    Repository Root: https://tc-svn.tencent.com/isd/isd_qzoneplatformdev_rep

    Repository UUID: df2599cb-4e79-6a4a-84f3-a1dd8b66c2e7

    Revision: 166688 <- 最新版本号

    Node Kind: directory

    Last Changed Author: reanshen

    Last Changed Rev: 166688

    Last Changed Date: 2013-04-12 19:07:17 +0800 (Fri, 12 Apr 2013)

    命令

    svn copy TRUNK_URL BRANCH_URL –m ”Create branch from trunk %REVISION%”

    作用

    创建分支

    示例

    svn copy $PHOTO_REPO/trunk $PHOTO_REPO/branches/photo_xxxx -m “Create branch from trunk 166688”

    结果

    Committed revision 166690.

    命令

    svn co SVN_URL[@REVISION]  [PATH]

    作用

    把svn库中的代码检出到本地,进行开发,编译

    SVN_URL: 想要检出的代码URL路径

    REVISION: 想要检出的版本号

    PATH: 想要将检出代码存放在何处。不填,则将URL最后一段作为文件夹名

    示例

    svn co $PHOTO_REPO/branches/photo_xxxx

    结果

    检出代码到当前目录下的photo_xxxx下

    命令

    svn commit [PATH] –m “comments”

    作用

    提交开发的代码

    示例

    svn commit . –m “add test cases”

    结果

    提交了当前目录内的修改

    命令

    svn merge TRUNK_URL [–dry-run]

    作用

    将主干改动同步到分支。svn1.5引入“合并跟踪”技术,让我们不再需要每次自己查找哪些版本需要同步到分支。svnbook中称这种合并技术为sync-merge。对于之前需要手动跟踪版本合并范围,效率的提升不是一点点。

    前置条件:本地代码库保证无任何未提交改动(用svn status查看);使用svn update更新到分支最新版本。

    --dry-run选项:可以尝试合并,但不修改本地代码。可以借此先看看冲突多不多。

    不加—dry-run选项: 进行真实的合并,修改本地代码,需要进行提交。

    示例

    svn merge  $PHOTO_REPO/trunk

    结果

    将主干上次合并后的改动自动同步到分支

    命令

    svn merge –reintegrate BRANCH_URL

    作用

    将分支代码合并进主干。

    前置条件:主干中所有的更改都已合并入分支。主干的本地代码库无未提交的代码,并且使用svn update更新到最新版本。

    示例

    svn merge –reintegrate $PHOTO_REPO/branches/photo_xxxx

    结果

    分支中所有的改动均合入主干。

    无冲突时,OK,顺利合并;

    有冲突时,如果是文本冲突,有两种选择。

    1. 输入”l”启动配置的merge工具(详见”svn配置”一节)

    会用vimdiff打开左中右三个垂直并列窗口

    左:base版本(分支svn库中的版本)

    中:mine版本(有本地修改的版本)

    右:theirs版本(主干上的版本)

    1. 输入”p”推迟解决。之后用status可以看到哪些文件有冲突。

    如果是树冲突,用svn status可以看出来。

    $ svn status

    	A  +  C code/bar.c
    	      >   local edit, incoming delete upon update
    	Summary of conflicts:
    	  Tree conflicts: 1

    如何解决树冲突,视乎具体情况而定。

    例如:主干上该文件被删除,则在分支上先使用svn delete删掉文件,再用svn resolve –accept working 解决冲突。

    命令

    svn delete BRANCH_URL –m “remove branch, reintegrated with trunk in r%REVISION%”

    作用

    分支合入主干后就不能继续使用,否则再次从主干合入分支会造成大量树冲突。

    清理掉svn数据库中的分支,让代码库更整洁一些,避免隐患。

    示例

    svn delete $PHOTO_REPO/branches/photo_xxxx  

    -m "remove branch, reintegrated with trunk in r16666"

    结果

    Committed revision 166702.

    分支从版本库中删除

    命令

    svn copy BRANCH_URL@LAST_REVISION BRANCH_URL –m “resurrect branch photo_xxxx@%LAST_REVISION”

    作用

    这时候有人问了,“万一我需要看某个分支改了哪些东西,删掉分支后我怎么看呢”?

    不用担心,分支一旦出现就永远不会消失,我们只是让它隐藏而已。真的需要时,可以轻易让它复活。如此命令所示,其中分支最后存在的版本号可以通过svn log branches父目录获得

    示例

    svn copy

    $PHOTO_REPO/branches/photo_xxxx@166701 $PHOTO_REPO/branches/photo_xxxx -m "resurrect branch photo_xxxx@166701"

    结果

    复活分支

    大体的svn工作流程如上所示,下面是其他一些通用操作。

    命令

    svn update

    作用

    将svn库中的代码更新到本地代码库

    示例

    svn up

    结果

    命令

    svn resolve –accept [working | theirs-full | mine-full |base] filename

    作用

    冲突解决

    --accept是个选择器

    base: 选择上次最新checkout的版本(未作本地修改的)

    mine-full: 选择仅包含自己本地修改的版本,忽略来自服务器的代码改动

    theirs-full: 选择仅包含来自服务器的代码改动,忽略自己本地的改动

    working: 选择手动merge完成后的版本

    示例

    结果

    命令

    svn status [-v]

    作用

    查看本地文件状态,可以看到当前目录下所有的改动

    -v: 可以显示所有的文件信息,包括未修改的。

    -u: 可以用”*”标识有更新的文件

    示例

    svn status

    结果

    ?       scratch.c (不在版本控制中)

    A       stuff/loot (新加文件,未提交)

    A       stuff/loot/new.c

    D       stuff/old.c (删除文件,未提交)

    M       bar.c (修改文件,未提交)

    C        cc.c (有冲突未解决的)

    命令

    svn log . –stop-on-copy –l N [-v]

    作用

    查看svn记录

    --stop-on-copy: 在分支从主干分出时停止

    -l N: 显示最多N个版本的Log

    -v: 显示详细的改动(文件改动)

    示例

    svn log . –stop-on-copy –l 1 -v

    结果

    ------------------------------------------------------------------------

    r164717 | philchen| 2013-03-29 09:22:23 +0800 (Fri, 29 Mar 2013) | 2 lines

    Changed paths:

       M /QzonePhoto_proj/branches/photobuild_xxxx/application/qqphoto/comm/photo_log/include/monitor_id_define.h

    命令

    svn diff [filename]

    作用

    未指定filename: 查看当前目录的所有更改

    指定filename: 查看指定文件的修改

    示例

    svn diff

    结果

    如果未配置diff-cmd, 默认使用svn自带的diff工具,输出格式如下

    Index: bar.c

    ===================================================================

    --- bar.c    (revision 3) [‘-‘标识前一版本的]

    +++ bar.c (working copy) [‘+’标识当前本地文件的]

    @@ -1,6 +1,7 @@[解释:’-‘标识前一版本,”1,6”指显示从第一行开始,共显示6行;’+’标识当前版本,”1,7”指显示从第一行开始,共显示7行]

    #include<stdlib.h>   [前面无标注,为公共行]

    +#include <stdio.h>   [前面为’+’,为当前本地文件的改动]

     int main(void) {

    -  printf("Sixty-four slices of American Cheese... "); [前面为’-‘, 为前一版本的改动]

    +  printf("Sixty-five slices of American Cheese... ");

     return 0;

     }

    如果配置了diff-cmd, 就使用配置的。详见”svn配置”一节。

    命令

    svn add FOO

    作用

    把FOO(文件,目录,符号链接)加入到版本库。添加目录时目录下面的所有东西都被加进来,除非文件的后缀在svn::ignore里面。

    示例

    svn add newproj/

    结果

    命令

    svn delete FOO

    作用

    把FOO(文件,目录,符号链接)从版本库中删除。文件或者符号链接会立即从文件系统中删除。

    示例

    svn del newproj/

    结果

    svn配置

    配置diff工具(vimdiff)

    作用:在命令行近似于ui方式较直观显示差异

    打开~/.subversion/config, 编译diff-cmd选项。

    diff-cmd = /usr/local/py/diffwrap.py

    diffwrap.py内容如下

    #!/usr/bin/env python

    import sys

    import os

    DIFF = "/usr/local/bin/vimdiff"

    # Subversion provides the paths we need as the last two parameters.

    LEFT  = sys.argv[-2]

    RIGHT = sys.argv[-1]

    # Call the diff command (change the following line to make sense for

    # your diff program).

    cmd = [DIFF, LEFT, RIGHT]

    os.execv(cmd[0], cmd)

    当使用一个外部的diff命令时,Subversion会生成一个非常复杂的命令行。第一个参数就是具体的--diff-cmd,然后就是具体的 --extensions (尽管使用空白的 --符号时会忽略扩展),或者如果没有指定--extensions或者--extensions为空的话,就加上‘-u’参数。第三和第四个参 数,Subversion会传递一个“-L”还有第一个文件的标签(例如,“"project_issues.html (revision 11209)”)。第五个和第六个就是另一个“-L”和第二个文件的标签。第七和第八个参数分别是第一个和第二个文件的名称(例如,“.svn/text-base/project_issues.html.svn-base”和“.svn/tmp /project_issues.html.tmp”)。

    配置merge工具(vimdiff)

    作用:在命令行近似于ui方式较直观显示差异

    左:base版本

    中:merged编辑区

    右:来自外部的版本

    打开~/.subversion/config, 编译merge-tool-cmd选项。

    merge-tool-cmd=”/usr/local/py/mymerge.py”

    然后编辑mymerge.py

    #!/usr/bin/env python

     

    import sys

    import shutil

    import subprocess

     

    try:

    # Configure your favorite merge program here.

    MERGE = “/usr/local/bin/vimdiff”

       

    # Get the paths provided by Subversion.

    BASE   = sys.argv[1]

    THEIRS = sys.argv[2]

    MINE   = sys.argv[3]

    MERGED = sys.argv[4]

     

    # Replace ‘merged’ file with a copy of ‘mine’

    shutil.copy(MINE, MERGED)

       

    cmd = [MERGE, BASE, MERGED, THEIRS]

    subprocess.check_call(cmd)

    except:

    sys.exit(1)

    vimdiff用法

    窗口焦点切换,即切换当前窗口

    CTRL-w h 跳转到左边的窗口

    CTRL-w j 跳转到下面的窗口

    CTRL-w k 跳转到上面的窗口

    CTRL-w l 跳转到右边的窗口

    CTRL-w t 跳转到最顶上的窗口

    CTRL-w b 跳转到最底下的窗口

    CTRL-w w 跳转到另一个窗口

    CTRL-w CTRL-w 跳转到另一个窗口,同CTRL-w w

    光标移动

    移动光标,切分窗口会同步移动,使用:set noscrollbind命令可取消同步

    ]c 跳到下一个不同的地方

    [c 跳到上一个不同的地方

    上下文折叠

    默认情况下,vimdiff会将文件中不同之处上下6行之外的相同文本折叠隐藏,可通过 :set diffopt=context:3 修改显示的上下文行数。

    zo 打开折叠

    zc 关闭折叠

    文件合并

    dp 将当前窗口光标位置处的内容复制到另一窗口

    do 将另一窗口光标位置处的内容复制到当前窗口

    diffupdate 重新比较两个文件,如果手动修改文件的话有时不会自动同步

    文件操作

    yy 复制当前行

    nyy 复制当前行开始的n行

    dd 删除当前行

    ndd 删除当前行开始的n行

    p 粘贴

    u 撤销

    CTRL-r 重复(即取消撤销)

    wa 全部保存

    wqa 全部保存后退出

    qa 全部退出

    qa! 全部强制退出,不保存文件修改

  • 相关阅读:
    java基础知识--环境变量配置
    安装oracle11g时遇到INS-13001环境不满足最低要求
    MINA系列学习-IoBuffer
    MINA系列学习-mina整体介绍
    DBCP数据源连接池实现原理分析
    dbcp数据源配置杂谈
    Java 内存区域和GC机制分析
    网站的防盗链与反盗链的那点事
    这一天博客小院我进来了!
    AOP
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/5554544.html
Copyright © 2011-2022 走看看