Translation

常见分支模式(译)

##前言

今天在将分支合并回 trunk 的时候,发现之前采用的分支模式不太合适,于是去查阅了 SVN 的用户手册 Version Control With Subversion - Common Branching Patterns,对分支管理有了更全面的认识。

版权声明:本文翻译自 Ben Collins-Sussman, Brian W. Fitzpatrick, C. Michael Pilato 撰写的 Version Control With Subversion。这是一本自由书籍,遵循 Creative Common Attribution License,这里是它的版权协议,本译文同样遵循此协议。

##译文

使用分支 (branch) 和合并 (merge) 的方式有很多,本节介绍了其中最常用的几种。

版本控制是在软件开发中最常用到的概念,所以我们来看一下被开发团队们最常用到的分支/合并模式。如果你在软件开发中并没有用 Subversion 来做版本控制,直接略过这一节就好。如果你是第一次在软件开发中使用版本控制,那请格外注意,因为这些模式通常已被认为是最佳实践。这些模式并不是 Subversion 才独有的,而是适用于任意的版本控制系统。我们以 Subversion 来描述这些模式,让它更容易理解。

###用于发布的分支 (Release 分支)

大多数软件都遵循这样的生命周期:编码,测试,发布,如此循环往复。在这个过程中存在两个问题。第一,在质量保证团队测试稳定版本的同时,开发团队依然需要继续开发新的功能。当软件在接受测试时,新的开发工作不能停顿。第二,开发团队大多都需要支持较老的、已经发布出去的版本。如果在较老的代码中发现了 bug,这个 bug 很有可能也存在于已经释出的版本中。客户想要马上修复它,而不用等待下一个大版本发布时才能解决。

这两个问题借助版本控制可以解决。以下是经典的过程:

  1. 开发者将所有新工作提交到 trunk 上。 每日的改变都被提交到 /trunk :包括新功能、bug 修复等。
  2. 复制 trunk 到一个 “release” 分支。 当团队认为软件可以发布的时候(比如,发布 1.0 版本),/trunk 会被拷贝到 /branches/1.0
  3. 团队继续并行工作。 一个团队开始对 release 分支进行严格的测试,同时,另一个团队在 /trunk 继续新的工作(比如,开发 2.0 版本)。无论哪一个团队发现了 bug,在必要的时候,对于这个 bug 的修复都可以移植 (ported) 到另一个团队。这个过程在某个时间点会停止,然后这个分支将会被“冻结”,以供发布前进行最终测试。
  4. 标记这个分支 (tagged) 并发布。 当测试结束后,为 /branches/1.0 创建一个标记到 /tags/1.0.0 ,作为一个引用快照。这个 tag 中的版本将会被打包并发布给用户。
  5. 这个分支随着时间的推移进行适当的维护。 2.0 版本的开发工作在 /trunk 中继续,修复的 bug 也陆续从 /trunk 中移植到 /branches/1.0 。当修复的 bug 数量累积到足够多的时候,管理层可能决定发布 1.0.1 版本,此时应把 /branches/1.0 创建标记到 /tags/1.0.1 ,这个 1.0.1 的 tag 会被打包发布。

这整个过程将随着软件的成熟而不断反复进行:当 2.0 的工作完成后,一个新的名为 2.0 的 release 分支会被创建、测试、标记,最终发布。几年后,整个 repository 将会是好多个处于“维护”模式的 release 分支,和好多个标志着最终发布给用户的 tag。

###用于新特性的分支 (Feature 分支)

用于新特性的分支 (feature branch) 是在这一章最合适的例子(当 Sally 继续在 /trunk 工作时,你需要开发一个新功能)【译者注:请参见原文在本节之前创设的情境】。这时一种临时的分支,用于进行一些复杂的修改,而不会影响到 /trunk 的稳定。不像 release 分支(需要永久支持),feature 分支的生命历程是:创建,使用它来进行新特性的开发,合并回 trunk,然后被永久删除。它们的作用是有限的。

另外,什么时候需要创建 feature 分支是不一定的,与不同工程的不同情况有关。有些工程从来不使用 feature 分支:所有人都可以自由地向 /trunk 提交。这种系统的好处是非常简单--不需要有人懂得有关分支和合并的知识。缺点是 trunk 的代码经常是不稳定的甚至是不可用的。而有些工程将分支用到了极致:所有的修改都 从不 直接提交到 trunk。即使是最微不足道的修改,也需要专门创建一个短命的分支,仔细审查,然后合并回 trunk。然后这个短命的分支就被删除了。这样可以保证在任何时间 trunk 都绝对稳定并可用,但是导致了大量的流程开销。

大多数工程采用了折中的方式。这种方式坚持 trunk 在任何时间都可以正常编译并通过回归测试。只有当某次修改包含大量提交,可能造成不稳定时,才需要创建 feature 分支。一个好的判断准则是:如果一个功能需要开发者独立工作好几天,然后一次性提交大量的修改(因为要保证 trunk 的稳定,所以要一次性),那这样的修改是不是大到需要进行代码审查了?如果对这个问题的回答是肯定的,那这些修改就应该在一个 feature 分支中进行。这样,开发者就能以递增的方式向 feature 分支中多次提交,而不必担心影响稳定,其他人也可以很容易地审阅到分支中这些代码的变化情况。

最后还有一个问题,如何在工作的进程中保持 feature 分支和 trunk 的同步。正如我们之前所说,在一个分支上工作数周甚至数月是有很大风险的;trunk 上的修改越来越多,与 feature 分支中对应代码行的差距越来越大,从 branch 合并回 trunk 可能会变得噩梦一般。

可以通过时常将 trunk 的变更合并到 branch 来避免这种状况【译者注:合并不是单向的,可以从 branch 合并回 trunk,也可以从 trunk 合并到 branch,后者也被称为“同步”】。制定一个原则:每周一次,将上周 trunk 上的变更合并到 branch 中。

在某个时间点,你会准备将“已同步”的 feature 分支合并回 trunk 中。要做这件事,首先要进行最后一次同步,将 trunk 最新的修改同步到 feature 分支中。完成后,最新的 branch 和 trunk 除了你在 branch 上的修改之外,将是完全一致的。然后就可以通过 reintegrate 选项将分支合并回去了:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ cd trunk-working-copy
$ svn update
At revision 1910.
$ svn merge --reintegrate http://svn.example.com/repos/calc/branches/mybranch
--- Merging differences between repository URLs into '.':
U real.c
U integer.c
A newdirectory
A newdirectory/newfile
U .

另外一种理解这种模式的方法是,每周从 trunk 向 branch 的同步可以看作是在 working copy 中执行了 svn update ,最后的合并操作可以看作是在 working copy 中执行了 svn commit 。既然这样,working copy 不就可以认为是一种非常浅的、私有的分支吗?它就是一种特别的分支,每次只有很少的变更。

.DS_Store 的由来(译)

##前言
本文作者为原苹果工程师 Arno Gourdol,正是他主导了 Mac OS X 系统上 Finder 应用的开发。这篇文章为我们阐述了 .DS_Store 文件的由来,是个很不错的计算机历史小文章。原文链接:http://arno.org/arnotify/2006/10/on-the-origins-of-ds_store/

##译文
如果你是一个 Mac 用户,或者你曾经从 Mac 向 Windows 传输过文件,你可能会对一个名为 .DS_Store 的文件很熟悉。但这个名字是从何而来呢?

时间回到 1999 年,我在苹果公司担任 Mac OS X 系统内 Finder 应用的技术主管。在那时,Finder 的代码已有 8 年的历史,代码已经很难以维护。做任何改变都需要做大量的工作,而且常常会影响到两三个看似跟它无关的功能。所以在 Mac OS X 上我们决定,从设计开始,重写 Finder。

涉及到的工作之一,便是分离用户界面和核心功能,也就是后台代码。Finder 的后台会穷举文件、监视文件系统变化、处理元数据,包括图标的位置和文件夹设置。在内部,这两个部分被我们称作 Finder_FE 和 Finder_BE(Frontend 和 Backend)。

但是,没过多久我们就意识到,Finder 以外的应用也很可能需要调用 Finder 后台的功能。所以我们计划在将来某一天,让它成为一个公共的 API。由于我之前曾负责命名了 Icon Services 和 Navigation Services,所以我们决定把它命名为 Desktop Services(在那时,我们还曾考虑过把 Finder 改名为 “Desktop”)。因此,.DS_Store 这个名字,就是 “Desktop Services Store”(桌面服务存储) 的意思。我们在文件名之前添加了一个句点,以保证在 Unix 操作系统上,包括 Mac OS 上,被识别为一个隐藏文件。

个人认为这并不是一个好的名字,我曾希望找到一个描述性更好的名字,但已经太晚了 :)

另外,还有一个至今仍未被修复的 bug,会导致过度创建 .DS_Store 文件。仅当用户更改了视图设置或改变了目录内图标的位置时,这些文件才应创建。可惜的是,事情并没有如此发生,而是当某个目录被访问时,.DS_Store 文件就会被创建。

另外,Finder_BE,也就是 Desktop Services,不再只被 Finder 调用:Navigation Services(打开/保存对话框)现在也会调用它,在 Mac OS 的最初版本中并不是这样的。但现在,Desktop Services 的 API 依然没有完全开放出来。