合并
分支用来维护独立的开发支线,在一些阶段,你可能需要将分支上的修改合并到主干,或者相反。
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.
下一个需要注意的地方是,合并总是在工作副本中进行。如果你想要合并修改到分支,你必须检出该分支的工作副本,并且从这个工作副本使用 → 来调用合并向导。
通常来说,在没有修改的工作副本上执行合并是一个好想法。如果你在工作副本上做了修改,请先提交。如果合并没有按照你的想法执行,你可能需要撤销这些修改,命令SVN 还原 会丢弃包含你执行合并之前的所有修改。
这里有三个处理方法稍微不同的用例,如下所述。合并向导的第一页会让你选择你需要的方法。
- 合并一个版本范围
-
这个方法覆盖了你已经在分支(或者主干)上做出了一个或多个修改,并且你想将这些修改应用到不同分支的情况。
你要 Subversion 做如下事情: “计算[从]分支 A 的版本 1 [到]分支 A 的版本 7 所需的修改,并将这些改变应用到(主干或分支 B 的)工作副本。”
- 复兴分支
-
这个用例覆盖了这种情况,当你象《Subversion手册》里讨论的那样,创建了一个新特性分支。所有主干的修改都要每周一次合并到新特性分支,等新特性完成后,你想将它合并到主干。因为你已经保持了新特性分支和主干同步,所以除了你在分支做的修改,其它部分在分支和最新版本应该是相同的。
这是下面讨论的树合并的特殊情况,它只需要你(通常情况下)想要合并的开发分支的 URL。它使用 Subversion 的合并跟踪特性来计算正确的版本范围,并且执行附加的检查来确保分支按照主干的修改进行了完整的更新。这样会确保你不会意外的撤销提交内容,这些内容是其他人在你上次同步修改后提交到主干的。
合并之后,分支的所有开发被完整的合并到主开发版本。现在的分支已经是多余的,可以删除。
一旦你执行了复兴合并,你就不应该继续使用它来进行开发。这样做的原因是,如果过后你试图再次对现有的分支与主干进行同步,合并跟踪将会你的复兴合并视为未合并到分支的主干修改,并且试图将分支到主干的合并再合并回分支!解决方案很简单,从主干创建一个新的分支来进行下一阶段的开发。
- 合并两个不同的树
-
这是复兴合并的通用情况。你要 Subversion 做如下事情: “计算[从]主干的最新版本[到]分支的最新版本所需要的修改,并将这些修改应用到(主干的)工作副本。”最终结果就是主干看起来与分支一模一样。
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.
在从:文本框中输入分支或标记文件夹的完整
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,10@3
. 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.
如果其他用户可能提交,那么要小心使用最新版本。如果有人在你最近更新之后提交了,它指代的版本可能就不是你想的那样了。
点击“合并选项”一节 。
跳转到
为了将一个特性分支合并到主干,您必须从一个主干工作副本启动合并向导。
在 从 URL: 区域输入您要复兴合并的分支的完整文件夹地址。你也可以点击 浏览版本库。
复兴合并需要满足一些条件。首先,服务器必须支持合并跟踪。工作副本必须为完全递归 (不是有限的检出深度),而且它不能具有任何本地修改、交换项目或已更新为最新版本之外的其他版本的项目。分支开发过程中的所有主干更改必须已合并到分支 (或标记为已合并)。要合并的版本范围将自动被计算。
如果您正使用此方法将一个特性分支合并回主干,你需要从一个主干工作副本内启动合并向导。
在 起始: 区域输入 主干 的完整文件夹地址。这听起来像是错了,但请记住主干是要添加分支更改的起始点。你也可以点击 浏览版本库。
在到:域输入关注的分支中文件夹的全路径。
在开始版本和结束版本 域,输入两个树被同步的最后一个版本号。如果你确信没有其他人提交,两个都可是输入 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.
您可以指定处理行结束和空白变化的方式。这些选项在 “行结束符和空白选项”一节 中被描述。默认情况是把所有的空白和行结束差异当做将被合并的真实更改。
标记为 强制合并 的复选框用于避免树冲突,传入的删除操作会影响到本地修改或不受版本控制的文件。如果删除了该文件,则无法恢复,这就是为什么在默认情况下未选中该选项。
如果您正在使用合并跟踪并且要将一个版本标记为已合并,而实际上并没有执行合并,那么就选中 只记录合并 复选框。您这样做可能有两个原因。合并过于复杂,合并算法表示压力很大,因此您选择手动更改代码,然后将更改标记为已合并,以便于合并跟踪算法也能识别到。或者您可能想要防止某个特定版本被合并,将其标记为已合并就可以用合并跟踪识别客户端来阻止合并的发生。
现在一切就绪,你要做的就是点击 不会 修改工作副本。它会显示一份会被真正合并的文件列表,并通告那些 可能 发生冲突的文件。因为合并跟踪会使合并过程变得更为复杂,没有任何方法可以事先保证完成合并时是否会出现冲突,所以在测试合并中标记为冲突的文件可能在实际的合并中并不会出现任何问题。
按钮。如果想要预览结果, 可以模拟合并操作,但完全合并进度对话框中会显示每个合并阶段,附带所涉及的版本范围。这可能意味着有超出你预料的更多版本。例如,如果你要求合并版本 123,进度对话框将报告为 “Merging revisions 122 through 123”。要理解这一点需要记住合并跟差异是密切相关的。合并进程的工作方式是在版本库两个点之间生成一份差异列表,并将这些差异应用至您的工作副本。进度对话框仅显示差异的开始点和结束点。
现在已完成合并。查看合并是否按预期完成是个不错的主意。合并通常是相当复杂的。如果分支跟主干偏差太大,往往会出现冲突。
提示
Whenever revisions are merged into a working copy, TortoiseSVN generates a log message from all the merged revisions. Those are then available from the
button in the commit dialog.To customize that generated message, set the corresponding project properties on your working copy. See“Merge log message templates”一节
对于 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.
合并不会总是顺利的。有时会有冲突,如果您正在合并多个范围,您通常要在下一个范围的合并开始之前解决冲突。TortoiseSVN 会在进程中通过显示 合并冲突回调 对话框来帮助你解决。
很可能某些更改将顺利进行合并,而其他的本地更改会跟已提交到版本库的更改发生冲突。所有可以合并的更改都将被合并。合并冲突回调对话框会给你您三种不同的方法来处理冲突的行。
-
If your merge includes binary files, merging of conflicts in those is not possible. You have to choose one complete file. UsePrefer local to select the local version as it was in your working copy prior to the merge, or Prefer repository to select the incoming file from the merge source in the repository.
If you are merging text files then these first two buttons allow you to merge non-conflicting lines as normal and always prefer one version where there are conflicts. Choosing Prefer local will select your local version in every conflict, i.e. it will prefer what was already there before the merge over the incoming change from the merge source. Likewise, Prefer repository will select the repository changes in every conflict, i.e. it will prefer the incoming changes from the merge source over what was already in your working copy. This sounds easy, but the conflicts often cover more lines than you think they will and you may get unexpected results.
-
通常情况下,你会想看看冲突和自己解决他们。在这种情况下,选择
将启动合并工具。当你对结果满意时,请点击 。 -
最后一个选项就是延迟解决并继续进行合并。您可以为当前的冲突文件做这样的选择,或者为合并余下部分的所有文件。但是,如果该文件在接下来的合并中有进一步的更改,它将无法完成合并。
如果您不想使用交互式回调,在合并进度对话框中有一个 非交互式合并 复选框。如果选中它,若合并中出现了冲突,该文件会被标记为冲突,然后继续合并。你必须在整个合并完成后解决这些冲突。如果不选中它,那么在冲文件被标记为冲突之前你有机会在合并 过程中 解决冲突。它的优势是如果一个文件获得多个合并 (多个修订版本将更改应用于该文件),后续的合并是否成功取决于受影响的行。但这样在合并期间你可不能离开去尿尿哦 ;)
如果您要从分支合并所有更改至主干,您可以从扩展的上下文菜单 (按住 Shift 键同时右击该文件) 中使用 → 。
此对话框很简单。你所要做的就是设置合并选项, 如 “合并选项”一节 中所述。剩下部分是通过
TortoiseSVN 自动使用合并跟踪来完成。
当您在一个特性分支上开发一项新特性并完成时,为其重新整合至主干制定一个策略是一个好主意。如果同一时间 主干
上有其他工作也在继续,您可能会发现随着时间推移,差异会变得更显著,复兴合并将成为一场噩梦。
如果新特性较为简单并且开发时间较短,那么您可以采取一种简单的方法,就是将分支完全独立,直到完成该特性,然后将分支更改合并回主干。在合并向导中,选择简单的 合并一个版本范围,该版本范围即是分支的版本跨度。
如果该特性需要花费更长的时间,就要考虑到 主干
中的变化,那么你就需要保持分支同步。这仅仅意味着定期地将主干的修改合并到分支,使分支包含所有主干的修改并 加上 新特性。同步过程使用 合并一个版本范围 。当完成新特性时,那么你可以使用 复兴分支 或 合并两个不同的树 将其合并回 主干
。