5.17. 正在合并

分支用来维护独立的开发支线,在一些阶段,你可能需要将分支上的修改合并到最新版本,或者将最新版本的修改合并到分支。

因为分支与合并很复杂,所以在你开始使用之前,请先理解它是怎么工作的。强烈建议你阅读《使用 Subversion 进行版本管理》的分支与合并章节,它给出了全面的描述,和许多使用举例。

十分关键之处是Subversion的合并与差异关系很密切。合并工作的基础是在版本库对两个分支产生一个差异列表,然后对你的工作副本应用这些差异。举例说明,如果你需要合并版本N的修改,那么你要与版本N-1比较。新手经常问“为什么我需要从开始版本减一”。考虑底层的差异处理,这个问题就会清楚了。为了容易操作,当你使用显示日志选择一个版本范围合并的时候,TortoiseSVN 自动为你做这个调整。

通常来说,在没有修改的工作副本上执行合并是一个好想法。如果你在工作副本上做了修改,请先提交。如果合并没有按照你的想法执行,你可能需要撤销这些修改,命令恢复 会丢弃包含你执行合并之前的所有修改。

这里有两个处理稍微不同的用例,如下所述。

5.17.1. 合并指定版本范围

这个方法覆盖了你已经在分支(或者最新版本)上做出了一个或多个修改,并且你想将这些修改应用到不同分支的情况。

图 5.32. 合并对话框

合并对话框

为了合并版本,你需要进入接收修改的分支的工作副本,经常是trunk。选择右键菜单TortoiseSVN合并...

  1. 从:域输入文件夹在分支或标记中的完整URL,它包含了你想应用到工作副本的修改。你也可以点击...浏览版本库,找到渴望的分支。如果你以前已经从这个分支合并过,可以直接从包含历史的下拉列表选择以前使用的URL。

  2. 因为你要将同一分支的版本范围合并到工作副本,所以要确保使用 "从:" URL 检查框选中。

  3. 从版本域输入开始版本号。它是在你要执行合并的修改之前的版本号。切记为了合并,Subversion将会创建一个差异,所以开始点务必准确。 例如,你的日志象这样:

    版本 注释
    39. Working on MyBranch
    38. Working on trunk
    37. Working on MyBranch
    36. Create branch MyBranch
    35. Working on trunk
    34. Working on trunk
             ...
    

    如果你要将 MyBranch 的修改合并到 trunk,应该选择36作为开始版本,而不是象你想的是37。如果你选择37作为开始点,那么差异引擎将会比较结束点与版本37比较,这就丢失了版本37做的修改。如果这听起来很复杂,不要担心,在TortoiseSVN中有更简单的方法 ...

    选择版本范围最简单的方法是,点击显示日志,列出最近的修改和日志。如果你要合并单个版本的修改,直接选取那个版本。如果你要合并多个版本,就选择范围(使用通常的Shift-键)。点击确认,就会为你填写合并对话框的全部域,开始版本结束版本

    当选择了检查框 使用 "开始:" URL,只有按钮显示日志可用。这是因为显示日志对话框设置了全部开始:结束:版本。所以你只用上面说的多项选择方法即可。

    如果你已经从这个分支合并了一些修改,希望你在提交日志中注明最后一个合并的版本号。这时,你可以在工作服本上使用显示日志对话框跟踪日志。使用最后合并的版本号作为本次合并的开始版本。例如,你已经合并了版本37到39,那么本次合并你应该从版本39开始。

  4. 如果你没有使用显示日志对话框显示版本范围,那么你需要手工设置结束版本。在范围中输入你想合并的最后一个版本号。这经常是最新版本,尽管它不必是 - 你只想合并单个版本。

    如果其他用户可能提交,那么要小心使用最新版本。如果有人在你最近更新之后提交了,它指代的版本可能就不是你想的那样了。

  5. 点击合并按钮完成合并。

现在合并结束。察看合并,看看它是否如预期那样工作,是个好想法。合并通常很复杂,如果分支与最新版本差别很大,合并经常会出现冲突。

当你已经测试了修改,准备提交时,日志信息应当总是包含这次合并的版本信息。如果你以后需要执行合并,就需要知道已经合并了什么,因为你不想多次合并同一修改。不幸的是,合并信息不会存储在Subversion版本库中。阅读《使用 Subversion 进行版本管理》中的合并的最佳实践章节以获得更多信息。

分支管理很重要。如果你要保持这个分支与最新版本同步,你应当经常合并,这样分支和最新版本的差别就不会太大。当然,你仍旧应该遵循上面的说明,避免重复合并修改。

[重要]重要

Subversion不能进行文件与文件夹的合并,反之亦然 - 只能文件夹对文件夹,文件对文件。如果选择了文件,打开合并对话框,那么你必须在对话框中给出文件的路径。如果你选择了文件夹,打开合并对话框,那么你必须给出文件夹的对话框。

5.17.2. 合并两个不同的目录树

这个用例覆盖了这种情况,当你象《Subversion手册》里讨论的那样,创建了一个新特性分支。所有最新版本的修改都要每周一次合并到新特性分支,等新特性完成后,你向将它合并到最新版本。因为你已经保持了新特性分支和最新版本同步,所以除了你在分支做的修改,其它部分在分支和最新版本应该是相同的。于是在这种情况下,你应当用比较分支和最新版本的方法来合并。

为了将新特性从分支合并到最新版本,你需要进入最新版本的工作副本。在右键菜单选择 TortoiseSVN合并...

  1. 开始:域输入trunk文件夹的全路径。这听起来好象是错误的,但是切记 trunk 是你想增加分支修改的开始点。也可以点击 ...浏览版本库。

  2. 因为你在比较两个不同的树,确认没有选择使用 "开始:" 路径检查框。

  3. 结束:域输入关注的分支中文件夹的全路径。

  4. 开始版本结束版本 域,输入两个树被同步的最后一个版本号。如果你确信没有其他人提交,两个都可是输入 HEAD。如果在同步时可能有人提交的话,使用清楚的版本号以便面丢失最新提交。

    你也可以使用显示日志选择版本。注意这种情况下,你不能选择版本范围,所以此时你选择的版本会实际出现在版本域。

  5. 点击合并按钮完成合并。

这种情况下,因为新特性已经集成到最新版本,你不再需要这个新特性分支。新特性分支变成多余的,如果需要可以从版本库删除它。

5.17.3. 预览合并结果

如果你不信任合并操作,可以在允许它修改你的工作副本之前预览效果。有三个额外的按钮可以帮着你预览。

统一差异创建差异文件(切记合并基于差异),显示你的工作目录哪些行将要被修改。因为这是统一差异(补丁)文件,所以离开上下文,它经常很难读。但是对于小的修改,由于它将所有修改在一起显示,因此很有用。

差异显示修改文件列表。双击任一文件启动差异察看器。不像统一差异,它显示具有前后关系的详细修改信息。象统一差异那样,你看到的是开始版本:结束版本:之间的差异。它不显示应用此改变之后,你的工作版本如何改变。

演习运行执行合并操作,但是根本 修改工作副本。它显示在真实的合并中要修改的文件列表,还告诉你哪里会出现冲突。

5.17.4. 忽略祖先

大部分时候,你要合并文件的历史,所以要相对于公共祖先合并。有时你需要合并或许是有关系的文件,但是不在你的版本库中。例如,你已经将一个第三方库的版本1和2导入到两个单独目录。尽管它们逻辑相关,因为Subversion只看到你导入的文件,所以它不知道这些关系。如果你试图合并这两个树的修改,将会看到完全的删除和增加。让Subversion只使用路径差异,不关心历史差异,选中忽略祖先检查框。你可以在《使用 Subversion 进行版本管理》的关心或忽略祖先中阅读此主题的更多信息。