1 主版本

主版本是全局的。在任何版本上提交,主版本记录都会+1。因为这个特性,所以在一个分支上的某个文件的版本可能不是连续的,因为有部分版本是在其他分支上提交的。

2 目录结构

svn官方推荐的目录结构为三个

项目名
– trunk
– branches
– tags

其中,trunk用于存放项目的主干,branches用于存放各个分支,tags相当于发行版的快照

2.1 trunk

说明
即项目的主分支,我们要发行的版本都是源自于此。一般来说,要打包上正式机的功能、代码都要并版到主分支上来。
注意
周期长的项目不要再直接在主分支上coding,否则很容易和其他人的修改造成冲突。

情景一

  1. A在主分支写业务功能a,B也在主分支写业务功能b,a/b两个项目要同时上线;
  2. A写完了一部分,提交了一个工具类;
  3. B看到了这个工具类,觉得不错就用它来开发业务功能b;
  4. 上线前,A临时修改了工具类,改完了项目“红”了一大片,发现是B的代码用到了自己的工具类;A不熟悉业务功能b,只好找B改;B也困惑“说这个类不能改啊,不然我的代码又要重写了”;
  5. 结果是,两个人的两个业务功能,相互依赖了。要一起改完了才能上线,并且但是都延期了。

如何解决
很好办,及时更新分支上的最新代码,及时提交自己的最新代码。

情景二
程序员小李开发的新功能c,代码提交了;然后晚上要上小刘做的新功能d。那么新功能c的代码要不要上正式机呢?
而新功能c很特别:

  1. 需要添加配置文件,否则会报错;
  2. 需要在数据库添加新字段,否则报错;
  3. 小李功能只写到一半,改了公共代码,没测试过,尚未知道对其他地方有无影响;

这时候要打包上线简直是一种噩耗。因为根本无法过滤掉小李的功能c;

如何解决
很好办,没写完的功能不要乱提交。

what !? 情景一和情景二的解决方案,结论是完全相反的。也就是说,无论怎么样,都有存在一些匪夷所思的问题。

同一个仓库,每个人都能往里面扔东西,删东西。你不知道什么时候你的代码会影响别人,而你自己也会受到别人的代码影响;

这就是只有一个分支所带来的难题。

2.2 branches

说明
分支,相当于在主分支上的基础上,做一个与主干并行的支干。简单来说,可以理解为:

前提:

  • 大路(trunk)
  • 小路(branch)
  • 目的地(需求/上线)
  • 大路只有一条,小路有n多条,目的地都在大路上;

描述:
当大路(trunk)人太多太挤的时候,我们自己开一条小路(branch)先往前走着;因为目的地都在大路上,所以到最后走小路的人都要重新走回到大路上去,这样才能到达目的地。

流程如下图所示:

image.png

3.3 tags

说明
快照。其实也就是记录了每个release版本。tags不要去修改,一般是只读不改的。

3 创建分支/Tags

说明
创建分支不一定一定要从主分支创建分支,也可以从分支上创建新的分支。

流程
右键主分支,在弹出的菜单上选择Branch/tag

image.png

在ToPath处写上要生成的分支的地址,不需要提前手动创建文件夹,会自动创建好的。

需要注意的是:

  • 分支名语义要清晰,如chings-act-20180607;
  • 初始化信息要写好,记录好是从哪个分支创建的分支,原因是什么,记录清晰便于日后查看;

Head revision in the repository表示从最新版本创建分支;
若是选择specific revision repository选项,则可以从右侧的输入框选择某个特定的版本来创建分支;

然后点击OK即可

image.png

看到以下信息,就说明分支已经创建成功啦!

image.png

4 合并分支

不同分支之间是能够相互合并的,把一个分支上的修改内容合并到另外一个分支的过程叫做“合并分支(merge)”。

4.1 分支合并到主干

临时开启的分支上,功能做完的时候,若需要上线,可以将代码合并到主干上去。
流程
右击主干,在弹出的菜单上选择“Merge”

image.png

这时候会弹出一个选择框,不同版本可能不太一样。重点关注两个选项:

  • Merge a range of revisions
  • Reintegrate a branch

Merge a range of revisions
当你某个分支(trunk/branch)产生一个或者多个版本变化,你想要将这些变化合并到另外一个分支上的情景。
特点
你可以选择是合并某个版本还是多个版本的代码。这个选项可以将主干合并到分支,也可以将分支合并到主干上。

Reintegrate a branch
Reintegrate 的意思是“使…变得完整”,所以这个选项的意思是将某个分支变得完整。
特征
将某个分支上的所有改动合并到主干上去。
注意
合并前,主干上不能有待提交的变化,并且要处于最新版本。也就是说,并版前,trunk上该提交的全部提交,改update的就update。否则,SVN会阻止你进行merge。

image.png

因为我们在这里是要将分支合并到主干上去,所以选择
Reintegrate a branch;点击Next,将会弹出一个框。

image.png

from URL 处填写你要合并到主干的那个分支地址。

其余采用默认配置即可,然后继续Next

image.png

这时候会弹出一个选项,可以选择是否对空格进行比较等选项;

需要注意的是还有一个“Test merge”选项,这个选项是先进行合并测试,并不是真的进行合并。合并前建议可以用它来测试看看有多少冲突。

这时候,我们点击Merge按钮,就是真的开始合并了。

SVN的合并都是从SVN资源库中拉取代码与本地代码进行比较,然后将变化添加到本地的代码中(working copy)去。

所以点击merge以后,只是本地的代码进行了合并,只要你不提交,一切都还留有可挽回的余地。只有你merge以后,再次将本地代码commit以后,并版的结果才会真正的提交到SVN资源库中去。所以merge的时候大可以不必紧张。

OK,当你点击merge按钮以后,如果分支和主干的代码有冲突,会弹出一个选项框

image.png

再此,你可以选择合适的解决冲突的方案。,这里的冲突是针对于文件而言的。

Prefer local:出现冲突,以本地为主,只保留本地的文件,也就是以只保留trunk的,那么分支的修改就丢失了。

Prefer repository :以远程库的为主,因为刚刚远程库的地址填的是分支的,所以这里的意思就是只保留分支的改动。

Edit conflit:只要出现冲突,马上编辑冲突(弹窗一个选项框手动解决冲突),就和我们以前提交时解决冲突一个样。

Resolve later :先标记这个冲突,一会儿再解决。选择这个以后,下一个文件出现冲突的时候,还是会继续弹出这个弹窗的。

Resolve all later:暂时忽略所有的冲突,一会儿再统一解决。选这个的话,下个文件冲突也不是提示了。

我们在这里选择Resolve all later,然后得到merge的结果

image.png

Action列表示事件类型:如Conflicted(出现冲突),Updated(修改)等等;

Path:表示Action对应的文件或文件夹。

一般来说,不管是否冲突都要仔细检查一下改动。

检查Updated的改动,在Updated的行上右键

image.png

选择Compare with working copy,也就是将merge的结果与本地记录进行比较,如下图所示

30d5b7ca-fb5b-4f56-a6ec-037c79db776b

左侧是原来的记录,右侧是并版后的本地记录(working copy)。可以进行比对。黄色部分就是变动的部分。
右侧的working copy可以进行编辑的。

编辑后可以直接ctrl+s进行保存。

接下来,选择Conflicted的行解决冲突,同样右键冲突的行,点击Edict conflit,弹窗编辑框

image.png

弹窗分三个区域,左上方是远程资源库的文件记录,右上方式原来本地的文件记录(即主干的记录),正下方为两个版本的文件合并后的记录。

红色部分表示冲突部分。我们可以直接在正下方区域对结果进行编辑。

也可以采用上方的工具栏,重点有三个。

当你选择某一行的时候,可以选择以主干为主,也可以选择以分支为主。

当你编辑好了冲突以后,就可以点击工具栏的(黄色三角形+绿色小勾勾)的图形,表示该文件的冲突已解决。

值得注意的是,标记为冲突已解决以后,就不能再进来编辑冲突了。

还有一种Action类型,叫做Tree conflict,它也是一种冲突类型。这个类型产生的原因一般是因为本地或者分支修改了文件名,或者某个分支删除了文件,又或者是移动了文件的位置,再或者是提交了两个分支都在相同目录下两个同名的文件造成的…

image.png

如何解决 tree conflict
有时候只能做二选一的操作,要么保留远程的改动,要么保留本地的改动。有时候只能先标记为已解决然后再进行处理。
但是毫无疑问,遇到这种问题,要先和其他分支上的作者进行沟通,看看对方操作这个文件的原因是什么。再思考下一步应该如何解决冲突。

commit
当所有冲突文件都被Resolve,就可以上传本地的merge结果了。

右键,Commit,即可!

image.png

4.2 主干合并到分支

从要合并到的分支上右键,选择Merge
image.png

在弹出的选项框中选择Merge a range of revisions,然后Next

image.png

接下来,我们会看到选项框
URL to merge from :从哪个分支合并
Revision range to merge:选择从上面的分支的某个或者多个版本进行合并。留空则表示合并全部更新。

其他采用默认值即可。
然后Next,如下图所示
image.png

继续弹窗提示,选择默认Merge,或者TestMerge

image.png

看一下结果

image.png

如果有冲突,则就像是从主干合并到分支的步骤一样处理就可以了。

5 最佳实践

  1. 每个人都可以拥有自己的分支,在自己的分支上可以自由提交。
  2. 及时合并主干的改动到自己的分支上,防止累计过多的冲突,不便于处理。并且能够及时拿到其他人更新的最新代码。
  3. 主干只用作发布,不要直接在主干上进行开发。需要上线改动的时候,再从分支上合并过来。
  4. 自己合并自己的代码,才能最大程度的保障Merge的正确性。并且Merge完了以后要重新进行测试。
  5. 分支合并到主干上之后,确认无误后可以删除掉。