合并

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

It is important to understand how branching and merging works in Subversion before you start using it, as it can become quite complex. It is highly recommended that you read the chapter Branching and Merging in the Subversion book, which gives a full description and many examples of how it is used.

下一个需要注意的地方是,合并总是在工作副本中进行。如果你想要合并修改分支,你必须检出该分支的工作副本,并且从这个工作副本使用TortoiseSVN → 合并…来调用合并向导。

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

这里有三个处理方法稍微不同的用例,如下所述。合并向导的第一页会让你选择你需要的方法。

  • 合并一个版本范围

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

What you are asking Subversion to do is this: “ Calculate the changes necessary to get [FROM] revision 1 of branch A [TO] revision 7 of branch A, and apply those changes to my working copy (of trunk or branch B). ”

If you leave the revision range empty, Subversion uses the merge-tracking features to calculate the correct revision range to use. This is known as a reintegrate or automatic merge.

  • 合并两个不同的树

This is a more general case of the reintegrate method. What you are asking Subversion to do is: “ Calculate the changes necessary to get [FROM] the head revision of the trunk [TO] the head revision of the branch, and apply those changes to my working copy (of the trunk). ” The net result is that trunk now looks exactly like the branch.

If your server/repository does not support merge-tracking then this is the only way to merge a branch back to trunk. Another use case occurs when you are using vendor branches and you need to merge the changes following a new vendor drop into your trunk code. For more information read the chapter on vendor branches in the Subversion Book.

合并指定版本范围

图 4.54. 合并向导 - 选择版本范围

合并向导 - 选择版本范围

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

If you are merging from a renamed or deleted branch then you will have to go back to a revision where that branch still existed. In this case you will also need to specify that revision as a peg revision in the range of revisions being merged (see below), otherwise the merge will fail when it can't find that path at HEAD.

在待合并的版本范围文本框中输入你想合并的版本列表。它可以是单一版本,用逗号隔开的指定版本列表,或用横线(-)连接的版本范围,或这些形式的组合。

If you need to specify a peg revision for the merge, add the peg revision at the end of the revisions, e.g. 5-7,[email protected]. In the above example, the revisions 5,6,7 and 10 would be merged, with 3 being the peg revision.

重要

在 TortoiseSVN 中指定版本范围的方法与命令行客户端大相径庭。用最简单的方法来说明这一点,设想一条栅栏,有支撑柱和栅栏板。

在命令行客户端,你使用两个“支撑柱”版本来指定需要合并的修改,这两个版本指明了修改前修改后的点。

在 TortoiseSVN,你使用“栅栏板”来指定要合并的修改集。当你使用日志对话框来选择需要合并的版本时这样做的原因就很清晰,每个版本看上去就是一个修改集。

If you are merging revisions in chunks, the method shown in the Subversion book will have you merge 100-200 this time and 200-300 next time. With TortoiseSVN you would merge 100-200 this time and 201-300 next time.

这个区别在邮件列表中引起了热烈的讨论。我们知道它与命令行客户端不同,但是我们相信,对于大多数的图形界面用户来说,我们制定的方法更容易理解。

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

如果您要将更改往回合并 您的工作副本,以还原一个已提交的更改,选择要还原的版本并确保选中了 反向合并 框。

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

如果你在使用 Subversion 的合并跟踪特性,你就不需要记住已经合并了那些版本 - Subversion 将会帮你记录。如果不填写版本范围,所有未合并的版本将被选中。阅读“合并跟踪”一节

When merge tracking is used, the log dialog will show previously merged revisions, and revisions pre-dating the common ancestor point, i.e. before the branch was copied, as greyed out. The Hide non-mergeable revisions checkbox allows you to filter out these revisions completely so you see only the revisions which can be merged.

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

If you leave the range of revisions empty or have the radio button all revisions checked, then Subversion merges all not-yet merged revisions. This is known as a reintegrate or automatic merge.

复兴合并需要满足一些条件。首先,服务器必须支持合并跟踪。工作副本必须为完全递归 (不是有限的检出深度),而且它不能具有任何本地修改、交换项目或已更新为最新版本之外的其他版本的项目。分支开发过程中的所有主干更改必须已合并到分支 (或标记为已合并)。要合并的版本范围将自动被计算。

点击下一页跳转到“合并选项”一节

合并两个不同的目录树

图 4.55. 合并向导 - 树合并

合并向导 - 树合并

如果您正使用此方法将一个特性分支合并回主干,你需要从一个主干工作副本内启动合并向导。

在 起始: 区域输入 主干 的完整文件夹地址。这听起来像是错了,但请记住主干是要添加分支更改的起始点。你也可以点击 … 浏览版本库。

在到:域输入关注的分支中文件夹的全路径。

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

也可以使用 显示日志 选择版本。

合并选项

此向导页可以指定合并进程开始前的高级选项。一般情况下你可以直接使用默认设置。

您可以指定合并深度,也就是到工作副本的合并程度。深度条款在 “检出深度”一节

Most of the time you want merge to take account of the file's history, so that changes relative to a common ancestor are merged. Sometimes you may need to merge files which are perhaps related, but not in your repository. For example you may have imported versions 1 and 2 of a third party library into two separate directories. Although they are logically related, Subversion has no knowledge of this because it only sees the tarballs you imported. If you attempt to merge the difference between these two trees you would see a complete removal followed by a complete add. To make Subversion use only path-based differences rather than history-based differences, check the Ignore ancestry box. Read more about this topic in the Subversion book, Noticing or Ignoring Ancestry

您可以指定处理行结束和空白变化的方式。这些选项在 “行结束符和空白选项”一节

标记为 强制合并 的复选框用于避免树冲突,传入的删除操作会影响到本地修改或不受版本控制的文件。如果删除了该文件,则无法恢复,这就是为什么在默认情况下未选中该选项。

如果您正在使用合并跟踪并且要将一个版本标记为已合并,而实际上并没有执行合并,那么就选中 只记录合并 复选框。您这样做可能有两个原因。合并过于复杂,合并算法表示压力很大,因此您选择手动更改代码,然后将更改标记为已合并,以便于合并跟踪算法也能识别到。或者您可能想要防止某个特定版本被合并,将其标记为已合并就可以用合并跟踪识别客户端来阻止合并的发生。

现在一切就绪,你要做的就是点击 合并 按钮。如果想要预览结果,测试合并 可以模拟合并操作,但完全 不会 修改工作副本。它会显示一份会被真正合并的文件列表,并通告那些 可能 发生冲突的文件。因为合并跟踪会使合并过程变得更为复杂,没有任何方法可以事先保证完成合并时是否会出现冲突,所以在测试合并中标记为冲突的文件可能在实际的合并中并不会出现任何问题。

The merge progress dialog shows each stage of the merge, with the revision ranges involved. This may indicate one more revision than you were expecting. For example if you asked to merge revision 123 the progress dialog will report “ Merging revisions 122 through 123 ”. To understand this you need to remember that Merge is closely related to Diff. The merge process works by generating a list of differences between two points in the repository, and applying those differences to your working copy. The progress dialog is simply showing the start and end points for the diff.

预览合并结果

现在已完成合并。查看合并是否按预期完成是个不错的主意。合并通常是相当复杂的。如果分支跟主干偏差太大,往往会出现冲突。

提示

Whenever revisions are merged into a working copy, TortoiseSVN generates a log message from all the merged revisions. Those are then available from the Recent Messages button in the commit dialog.

To customize that generated message, set the corresponding project properties on your working copy. See “合并日志信息模板”一节

对于 Subversion 客户端和服务器 1.5 之前的版本,不会存储合并信息并且合并的版本必须手动进行跟踪。当您测试完更改来提交这次修订版本时,您的提交日志信息应该会 始终 包括在合并中已导入的版本号。如果以后要应用另一个合并,您需要知道你已经合并过的,因为没人愿意多次地导入更改。这有关的详细信息,请参阅 Subversion 书册中的 最佳的合并实践

如果你的服务器和所有客户端都使用 Subversion 1.5 或更高版本,合并跟踪工具会记录已经合并的版本,避免某个版本被合并多次。它会使你的生活更简单,因为你每次都可以简单的合并全部版本范围,并且知道只有新版本才会实际被合并。

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

提示

如果你刚刚将一个特性分支合并到主干,那么主干现在包含所有新的特性代码,分支就已经无用了。如果需要的话,现在可以从版本库中将其删除。

重要

Subversion 无法用一个文件夹来合并一个文件,反之亦然 - 只能是文件夹对文件夹,文件对文件。如果您点击一个文件并打开合并对话框,然后你必须在对话框中给出一个文件路径。如果您选择一个文件夹并打开对话框,然后您必须为合并指定一个文件夹地址。

合并跟踪

Subversion 1.5 引入了合并跟踪特性。当你合并版本树时,版本号会被保存,此信息可以用于几个目的。

  • 您可以避免合并同一版本两次的隐患 (重复合并问题)。一旦一个版本被标记为已合并,将来在版本范围中包含该版本的合并将会跳过它。

  • 当您合并一个分支到主干时,日志对话框可以将分支提交作为主干日志的一部分来显示,这样可得到对更改更好的跟踪性。

  • 当您从合并对话框内显示日志对话框时,已合并的版本显示为灰色。

  • 当显示一个文件的追溯信息时,你可以选择显示已合并版本的原作者,而不是合并者。

  • 您可以把版本标记为 不合并,通过把他们包含在已合并的版本列表中而实际上并没有进行合并。

执行合并时客户端将合并跟踪信息存储在 svn:mergeinfo 属性中。提交合并时,服务器会将该信息存储在数据库中,而当您请求合并、日志或追溯信息时,服务器可以作出恰当的响应。为了使系统正常工作,您必须确保服务器、版本库和所有客户端都是最新的。较早的客户端将不会存储 svn:mergeinfo 属性并且早期版本的服务器端不会提供新版客户端所请求的信息。

Find out more about merge tracking from Subversion's Merge tracking documentation.

Handling Conflicts after Merge

重要

The text in the conflict resolver dialogs are provided by the SVN library and might therefore not (yet) be translated as the TortoiseSVN dialogs are. Sorry for that.

Merging does not always go smoothly. Sometimes there is a conflict. TortoiseSVN helps you through this process by showing the merge conflict dialog.

图 4.56. The Merge Conflict Dialog

The Merge Conflict Dialog

It is likely that some of the changes will have merged smoothly, while other local changes conflict with changes already committed to the repository. All changes which can be merged are merged. The Merge Conflict dialog gives you different ways of handling the lines which are in conflict.

For normal conflicts that happen due to changes in the file content or its properties, the dialog shows buttons which allow you to chose which of the conflicting parts to keep or reject.

  • Postpone

Don't deal with the conflict now. Let the merge continue and resolve the conflicts after the merge is done.

  • Accept base

This leaves the file as it was, without neither the changes coming from the merge nor the changes you've made in your working copy.

  • Accept incoming

This discards all your local changes and uses the file as it arrives from the merge source.

  • Reject incoming

This discards all the changes from the merge source and leaves the file with your local edits.

  • Accept incoming for conflicts

This discards your local changes where they conflict with the changes from the merge source. But it leaves all your local changes which don't conflict.

  • Reject conflicts

This discards changes from the merge source which conflict with your local changes. But it keeps all changes that don't conflict with your local changes.

  • Mark as resolved

Marks the conflicts as resolved. This button is disabled until you use the button Edit to edit the conflict manually and save those changes back to the file. Once the changes are saved, the button becomes enabled.

  • 编辑

Starts the merge editor so you can resolve the conflicts manually. Don't forget to save the file so the button Mark as resolved becomes enabled.

If there's a tree conflict, please first see “树冲突”一节

To resolve tree conflicts after a merge, a dialog is shown with various options on how to resolve the conflict:

图 4.57. The Merge Tree Conflict Dialog

The Merge Tree Conflict Dialog

Since there are various possible tree conflict situations, the dialog will show buttons to resolve those depending on the specific conflict. The button texts and labels explain what the option to resolve the conflict does. If you're not sure, either cancel the dialog or use the Postpone button to resolve the conflict later.

特性分支维护

当您在一个特性分支上开发一项新特性并完成时,为其重新整合至主干制定一个策略是一个好主意。如果同一时间 主干 上有其他工作也在继续,您可能会发现随着时间推移,差异会变得更显著,复兴合并将成为一场噩梦。

如果新特性较为简单并且开发时间较短,那么您可以采取一种简单的方法,就是将分支完全独立,直到完成该特性,然后将分支更改合并回主干。在合并向导中,选择简单的 合并一个版本范围,该版本范围即是分支的版本跨度。

如果该特性需要花费更长的时间,就要考虑到 主干 中的变化,那么你就需要保持分支同步。这仅仅意味着定期地将主干的修改合并到分支,使分支包含所有主干的修改并 加上 新特性。同步过程使用 合并一个版本范围 。当完成新特性时,那么你可以使用 复兴分支 或 合并两个不同的树 将其合并回 主干

Another (fast) way to merge all changes from trunk to the feature branch is to use the TortoiseSVN → Merge all… from the extended context menu (hold down the Shift key while you right click on the file).

图 4.58. The Merge-All Dialog

The Merge-All Dialog

This dialog is very easy. All you have to do is set the options for the merge, as described in “合并选项”一节