SVN 分支/合并/切换

本文无条理性,仅作自我参考。

花费了两个半下午,走马观花的看了一下说明文档,SVN设计的太复杂,对我这样的,不在一个集体的的业余开发者,要理解起来真是太难了。。。。  


 

分支

Make branches as often as you want.(这是SVN官方说明中的一句话)

There's nothing special about this working copy; it simply mirrors a different directory in the repository.

版本控制系统的一个特性是能够把各种修改分离出来放在开发品的一个分割线上。这条线被称为分支。分支经常被用来试验新的特性,而不会对开发有编译错误的干扰。当新的特性足够稳定之后,开发品的分支就可以混合回主分支里(主干线).

假设已经建立分支,如果其他人的 working copy 在trunk上,当你提交分支的更改时,主干不会发生改变。

分支背后的关键概念:You should remember two important lessons.

First, Subversion has no internal concept of a branch—it knows only how to make copies.When you copy a directory, the resultant directory is only a “branch” because you attach that meaning to it. You may think of the directory differently,or treat it differently, but to Subversion it's just an ordinary directory that happens to carry some extra historical information.
在版本库中的复制,都是“廉价复制”。

Second, because of this copy mechanism, Subversion's branches exist as normal filesystem directories in the repository. This is different from other version control systems, where branches are typically defined by adding extra-dimensional “labels” to collections of files. The location of your branch directory doesn't matter to Subversion. Most teams follow a convention of putting all branches into a /branches directory, but you're free to invent any policy you wish.

合并(保持分支同步)

  ------frequently keeping your branch in sync with the main development line helps prevent “surprise” conflicts when it comes time for you to fold your changes back into the trunk.

由于有众多的人参与项目,大多数人拥有主干拷贝是很正常的,任何人如果进行一个长周期的修改会使得主干陷入混乱,所以通常的做法是建立一个私有分支,提交修改到自己的分支,直到这阶段工作结束。所以,好消息就是你和Sally不会互相打扰,坏消息是有时候分离会太远。

记住“闭门造车”策略的问题,当你完成你的分支后,可能因为太多冲突,已经无法轻易合并你的分支和主干的修改。

相反,在你工作的时候你和Sally仍然可以继续分享修改,这依赖于你决定什么值得分享,Subversion给你在分支间选择性“拷贝”修改的能力,当你完成了分支上的所有工作,所有的分支修改可以被拷贝回到主干。在Subversion术语里,这种从一个分支复制修改到另一个分支的活动称为合并,它是使用svn merge命令执行。

 

svn merge另一个常用的做法

是取消已经做得提交,假设你愉快的在/calc/trunk工作,你发现303版本对integer.c的修改完全错了,它不应该被提交,你可以使用svn merge来“取消”这个工作拷贝上所作的操作,然后提交本地修改到版本库,你要做得只是指定一个相反的区别。(你可以通过指定--revision 303:302--change -303

svn merge与svn  diff

......At this point, the wise thing to do is look at the changes carefully with svn diff, and then build and test your branch. Notice that the current working directory (“.”) has also been modified; the svn diff will show that its svn:mergeinfo property has been either created or modified. This is important mergerelated metadata(元数据) that you should not touch, since it will be needed by future svn merge commands.

但是svn merge没有这样的保证,会导致很多的混乱:用户可以询问服务器比较任何两个树,即使一个与工作拷贝毫不相关的!这意味着有潜在的人为错误,用户有时候会比较两个错误的树,创建的增量数据不会干净的应用,svn merge会尽力应用更多的增量数据,但是有一些部分也许会难以完成,就像Unix下patch命令有时候会报告“failed hunks”错误,svn merge会报告“skipped targets”:

指出svn diff和svn merge区别的重要性在于,前一个命令忽略祖先,如果你询问svn diff来比较文件foo.c的版本99和102,你会看到行为基础的区别,diff命令只是盲目的比较两条路径,但是如果你使用svn merge是比较同样的两个对象,它会注意到他们是不关联的,而且首先尝试删除旧文件,然后添加新文件,输出会是一个删除紧接着一个增加。

如果你使用svn merge进行比较,你会看到第一个目录树被删除,而第二个树添加上!在这个情况下,你仅仅是希望svn merge以路径为基础比较两棵树,而忽略文件和目录的不相关性,当为合并命令添加--ignoreancestry选项时,就会像svn diff一样工作。

 

切换

“Switching” a working copy that has no local modifications to a different branch results in the working copy looking just as it would if you'd done a fresh checkout of the directory. It's usually more efficient to use this command, because often branches differ by only a small degree. The server sends only the minimal set of changes necessary to make your working copy reflect the branch directory.

 

svn switch命令改变存在的工作拷贝到另一个分支,然而这个命令在分支上工作时不是严格必要的,它只是提供了一个快捷方式。在前面的例子里,完成了私有分支的建立,你取出了新目录的工作拷贝,相反,你也可以简单的告诉Subversion改变你的/calc/trunk的工作拷贝到分支的路径。

 

svn switch命令也可以带--revision(-r)参数,所以你不需要一直移动你的工作拷贝到分支的HEAD。
当然,许多项目比我们的calc要复杂的多,有更多的子目录,Subversion用户通常用如下的法则使用分支:
1. 拷贝整个项目的“trunk”目录到一个新的分支目录。
2. 只是转换工作拷贝的部分目录到分支。

切换和更新

Have you noticed that the output of svn switch and svn update looks the same? The switch command is actually a superset of the update command.

svn switch是svn update的一个变种,具有相同的行为,当新的数据到达时,任何工作拷贝的已经完成的本地修改会被保存。

 当你运行svn update时,你会告诉版本库比较两个目录树,版本库这样做,并且返回给客户区别的描述,svn switch和svn update两个命令唯一区别就是update会一直比较同一路径。That is, if your working copy is a mirror of /calc/trunk, svn update will automatically compare your working copy of /calc/trunk to /calc/trunk in the HEAD revision. If you're switching your working copy to a branch, svn switch will compare your working copy of /calc/trunk to some other branch directory in the HEAD revision.换句话说,一个更新通过时间移动你的工作拷贝,一个转换通过时间和空间移动工作拷贝。

 If the working copy needs to reflect(映射) a new directory within the repository, use just svns witch.If the working copy still reflects the same repository directory, but the location of the repository itself has changed, use svn switch with the --relocate option。


另一个Subversion模型的可爱特性是分支和标签可以有有限的生命周期,就像其它的版本化的项目,举个例子,假定你最终完成了calc项目你的个人分支上的所有工作,在合并了你的所有修改到/calc/trunk后,没有必要继续保留你的私有分支目录。

在我们的例子里,你的个人分支只有一个相对短的生命周期:你会为修复一个Bug或实现一个小的特性来创建它,当任务完成,分支也该结束了。在软件开发过程中,有两个“主要的”分支一直存在很长的时间也是很常见的情况,举个例子,假定我们是发布一个稳定
的calc项目的时候了,但我们仍会需要几个月的时间来修复Bug,你不希望添加新的特性,但你不希望告诉开发者停止开发,所以作为替代,你为软件创建了一个“稳定”分支...。

  


 

 

SVN可以为一个版本库中的内容(主干)建立一个分支.分支和主干完全独立,就相当于把代码再复制(便宜复制)一份,重新添加到版本库中。但SVN提供另一个功能,就是把主干做出的修改合并到分支中,以及把分支修改的内容合并到主干中。当然,我们也可以把主干的版本库的路径切换到分支上,然后更新,来实现把分支的修改更新到主干;以及修改分支路径来同步主干的修改。但过程复杂,还容易出错。

1.将一个整项目建一个分支.

选择要复制的源位置有三个选项:

  版本库中的最新版本
    新分支直接从仓库中的最新版本里复制出来。不需要从你的工作副本中传输任何数据,这个分支的建立是非常快的。
  在版本库中指定具体的版本
    在仓库中直接复制建立一个新分支同时你也可以选择一个旧版本。假如在你上周发布了项目时忘记了做标记,这将非常有用。如果你记不起来版本号,通过点击鼠标右键来显示版本日志,同时从这里选取版本号。和上次一样不需要从你的工作副本中传输任何数据,这个分支建立起来是非常快的。
  工作副本
    新的分支是一个完全等同于你的本地工作副本的一个副本。如果你更新了一些文件到你的工作副本的某个旧版本里,或者你在本地做出了修改,这些改变将准确无误的进入副本中。自然而然地这种综合的标记会包含正在从工作副本传输到版本库的数据,如果这些数据还不存在的话。

 

注意:是否把主干的路径切换到新分支(把的工作副本自动切换到最新创建的分支)

  如果勾选了,建立分支后,在主干里做出的修改并提交后,更新会提交到分支上。主干的版本源内容不会变.

  但是如果你打算这么做,首先要确认你的工作副本没有被修改。如果有修改的话,当你转换后这些修改将会混合进你的工作副本分支里。按下确认提交新副本到版本库中。别忘了提供一条日志信息。需要注意的是这个副本是在版本库内部创建的。

 

为了避免产生困惑。以及失误。建议在建立的时候不要勾上 "切换到分支" 的选项。如果勾上了,我们还是切换回去:

这时你便可以在 /calc/branches/my-calc-branch 分支上开发新的功能,且不会影响到其他成员开发或维护主干的内容。

切换操作起来就象更新,因为它没有丢弃你在本地做的修改。在工作副本里当你进行切换的时候任何没有提交过的修改都会被混合。如果你不想看到这样的结果,那么你可以有两种选择,要么在切换前提交修改要么把工作副本恢复到一个已经提交过的版本(比如最新版本)。

 

 

 

2.合并主干的变更到分支上

经常將 开发主干 ( /calc/trunk ) 的变更透过 svn merge 合并至 分支 ( /calc/branches/my-calc-branch )是一个非常好的习惯,这样才不会让你脱离主干(trunk) 过久而导致将分支 ( /calc/branches/my-calc-branch) 合并回 主干 ( /calc/trunk ) 时发生许多冲突。 

 

 从主干 ( /calc/trunk ) 合并至分支 ( /calc/branches/my-calc-branch ) 通常选第 1 个,也就是 [Merge a range of revisions]

注意.我们是在分支上使用的 Merge 功能.因为是要在分支上应用主干的更新.

 

 

在 Merge 的窗口有以下注意事項:

1.合并的来源,由于我们打算从主干 ( /calc/trunk ) 合并至分支 ( /calc/branches/my-calc-branch ),所以合并的來源要选 /calc/trunk 才对!
2.合并的结果会直接与目前「工作目录」(Working Copy) 做比对,并修改目前工作目录中的所有文件。因此建议在做合并之前可以将所有尚未 commit 的档案先 commit 到版本库,避免不必要的冲突事件发生。

 

在正式进行合并(Merge)之前,建议先执行 Test merge 看看是否会发生什么事!


若无异状则可直接按下 [Merge] 按钮进行合并动作,这时从 主干 ( /calc/trunk ) 分支出来的到目前工作目录的版本就会做个比较,然后直接套用变更到你现有的文件、目录或属性里。

 

在合并之后如果没有发生冲突,不代表真的没冲突,所以必须再次对原始码做出验证后才能 commit 进版本库,
建议可参考以下流程:
1.将项目进行建置(Build)
2.如果没问题再对项目进行单元测试(Unit Testing)或手动测试(Manual Testing)
3.如果都没问题再 commit 目前合并无误的版本到版本库!

 

If you encounter serious problems, you can always abort the local changes by running svn revert .

3.合并分支到主干

最后我们的 my-calc-branch 分支已经将新功能开发完成且测试无误,所以要将 分支 ( calc/branches/mycalc-branch ) 的最终版本合并回 主干 ( /calc/trunk ),这时的手续如下:

 

  

 

从 分支 ( /calc/branches/my-calc-branch ) 合并回 主干 ( /calc/trunk ) 通常选第 2 个,而特别选择[Reintegrate a branch] 这个选项是很重要的,因为这有以下好处:
1.让 Subversion 能知道 主干 ( /calc/trunk ) 是从哪个分支、哪些版本合并进来的
2.有效节省 Subversion Repository (SVN储存库) 的空间,因为不用重复储存分支的所有变更信息
3.可以产生 Revision graph 得知项目开发的分支状况

 

一样可以先 测试合并(Test merge) 再正式进行 合并(Merge)

 

 

4.合并完后再将变更 commit 到版本库

 

 

4.删除使用完毕的分支

当 分支 ( /calc/branches/my-calc-branch ) 合并回 主干 ( /calc/trunk ) 并 commit 了之后,该分支就没
用了,该分支如果未来不再更新或继续开发,Subversion 也不会继续追踪这个分支的变更 (因为之前已经
Reintegrate 过了),建议将该分支删除。

 

 

没有必要继续保留你的私有分支目录。删除已经完成的分支避免其他人继续使用该分支开发,减少版本库的复杂程度。

 

 

另参考:http://www.cnblogs.com/dabaopku/archive/2011/05/21/2052820.html

 

 

posted @ 2015-07-20 12:33  BingBox  阅读(5461)  评论(0编辑  收藏  举报