分支用于维护独立开发线路,在某个阶段,您需要将一个分支上所做的更改合并回主干,或反之亦然。
在使用 Subversion 的分支和合并功能之前,务必先了解其工作原理,因为它可能变得相当复杂。强烈建议您阅读 Subversion 书籍中 分支与合并 章节,其中详细描述了其用法并提供了许多示例。
接下来需要注意的是,合并 始终 在工作副本中进行。如果您想将更改合并 到 分支中,您必须检出该分支的工作副本,并使用 → 从该工作副本调用合并向导。
通常,最好在未修改的工作副本中执行合并。如果您在 WC 中进行了其他更改,请先提交这些更改。如果合并未按预期进行,您可能需要还原更改,并且 还原 命令将丢弃 所有 更改,包括您在合并之前所做的任何更改。
合并有三种常见的用例,处理方式略有不同,如下所述。合并向导的第一页会要求您选择所需的方法。
此方法涵盖了您对分支(或主干)进行了一个或多个修订版本的情况,并且您希望将这些更改移植到不同的分支。
您要求 Subversion 执行的操作是:“ 计算从分支 A 的修订版本 1 [到] 分支 A 的修订版本 7 所需的更改,并将这些更改应用到我的工作副本(主干或分支 B)。”
如果您将修订版本范围留空,Subversion 将使用合并跟踪功能来计算要使用的正确修订版本范围。这被称为重新集成或自动合并。
这是重新集成方法更通用的情况。您要求 Subversion 执行的操作是:“ 计算从主干的 HEAD 修订版本 [到] 分支的 HEAD 修订版本 所需的更改,并将这些更改应用到我的工作副本(主干)。” 最终结果是主干现在看起来与分支完全相同。
如果您的服务器/存储库不支持合并跟踪,那么这是将分支合并回主干的唯一方法。另一种用例是当您使用供应商分支时,并且您需要将新供应商交付后的更改合并到您的主干代码中。有关更多信息,请阅读 Subversion 书籍中关于 供应商分支 的章节。
在 从: 字段中,输入包含您要移植到工作副本的更改的分支或标签的完整文件夹 URL。您也可以单击 浏览存储库并找到所需的分支。如果您之前从此分支合并过,只需使用下拉列表,其中显示了以前使用过的 URL 的历史记录。
如果您要从重命名或删除的分支合并,则必须回到该分支仍然存在的修订版本。在这种情况下,您还需要在要合并的修订版本范围中指定该修订版本作为锚定修订版本(见下文),否则当它在 HEAD 找不到该路径时,合并将失败。
在 要合并的修订版本范围 字段中,输入您要合并的修订版本列表。这可以是单个修订版本,以逗号分隔的特定修订版本列表,或以破折号分隔的修订版本范围,或这些的任意组合。
如果您需要为合并指定锚定修订版本,请在修订版本末尾添加锚定修订版本,例如 5-7,10@3
。在上面的示例中,将合并修订版本 5,6,7 和 10,其中 3 是锚定修订版本。
TortoiseSVN 指定修订版本范围的方式与命令行客户端指定的方式存在重要差异。最简单的可视化方法是将围栏想象成带有柱子和围栏面板。
使用命令行客户端,您可以使用两个 “围栏柱” 修订版本来指定要合并的更改,这两个修订版本指定了 之前 和 之后 的点。
使用 TortoiseSVN,您可以使用 “围栏面板” 指定要合并的变更集。当您使用日志对话框指定要合并的修订版本时,原因变得清晰,其中每个修订版本都显示为变更集。
如果您按块合并修订版本,Subversion 书籍中显示的方法将使您这次合并 100-200,下次合并 200-300。使用 TortoiseSVN,您这次将合并 100-200,下次合并 201-300。
这种差异在邮件列表中引起了很多争议。我们承认与命令行客户端存在差异,但我们认为对于大多数 GUI 用户来说,更容易理解我们已实现的方法。
选择所需修订版本范围的最简单方法是单击 Shift 修改键)。单击 ,要合并的修订版本号列表将为您填写。
,因为这将列出最近的更改及其日志注释。如果您想合并单个修订版本的更改,只需选择该修订版本即可。如果您想合并多个修订版本的更改,请选择该范围(使用常用的如果您想将更改 移出 工作副本,以还原已提交的更改,请选择要还原的修订版本,并确保选中 反向合并 框。
如果您已经从该分支合并了一些更改,希望您在提交更改时在日志消息中记录了上次合并的修订版本。在这种情况下,您可以使用
来跟踪该日志消息。请记住,我们将修订版本视为变更集,您应该使用上次合并的结束点之后的修订版本作为本次合并的起始点。例如,如果您上次合并了修订版本 37 到 39,那么本次合并的起始点应该是修订版本 40。如果您正在使用 Subversion 的合并跟踪功能,则无需记住哪些修订版本已合并 - Subversion 会为您记录。如果您将修订版本范围留空,则将包含所有尚未合并的修订版本。阅读 “合并跟踪” 部分以了解更多信息。
当使用合并跟踪时,日志对话框将以灰色显示以前合并的修订版本,以及早于公共祖先点的修订版本,即分支复制之前的修订版本。隐藏不可合并的修订版本 复选框允许您完全过滤掉这些修订版本,以便您只看到 可以 合并的修订版本。
如果其他人可能正在提交更改,请谨慎使用 HEAD 修订版本。如果其他人在您上次更新后进行了提交,则它可能不指向您认为的修订版本。
如果您将修订版本范围留空,或者选中了 所有修订版本 单选按钮,则 Subversion 将合并所有尚未合并的修订版本。这被称为重新集成或自动合并。
重新集成合并有一些适用条件。首先,服务器必须支持合并跟踪。工作副本的深度必须是无限的(无稀疏检出),并且它不得有任何本地修改、切换项或已更新到 HEAD 以外的修订版本的项。在分支开发期间对主干所做的所有更改都必须已合并到分支(或标记为已合并)。要合并的修订版本范围将自动计算。
单击 “合并选项” 部分。
并转到
如果您使用此方法将功能分支合并回主干,则需要从主干的工作副本中启动合并向导。
在 从: 字段中,输入 主干 的完整文件夹 URL。这听起来可能不对,但请记住,主干是您要向其中添加分支更改的起点。您也可以单击 浏览存储库。
在 到: 字段中,输入功能分支的完整文件夹 URL。
在 起始修订版本 字段和 结束修订版本 字段中,输入两个树同步的最后一个修订版本号。如果您确定没有其他人在进行提交,则可以在两种情况下都使用 HEAD 修订版本。如果有可能自同步以来有人进行了提交,请使用特定的修订版本号以避免丢失更新的提交。
您也可以使用
来选择修订版本。向导的此页面允许您在启动合并过程之前指定高级选项。大多数情况下,您只需使用默认设置即可。
您可以指定用于合并的深度,即合并应深入到您的工作副本的程度。深度术语在 “检出深度” 部分中描述。默认深度为 工作副本,它使用现有的深度设置,并且几乎总是您想要的。
大多数情况下,您希望合并考虑文件的历史记录,以便合并相对于公共祖先的更改。有时您可能需要合并可能相关但不在您的存储库中的文件。例如,您可能已将第三方库的版本 1 和版本 2 导入到两个单独的目录中。尽管它们在逻辑上是相关的,但 Subversion 对此一无所知,因为它只看到您导入的 tarball。如果您尝试合并这两个树之间的差异,您将看到完整的删除,然后是完整的添加。要使 Subversion 仅使用基于路径的差异而不是基于历史记录的差异,请选中 忽略祖先 框。在 Subversion 书籍中阅读有关此主题的更多信息, 注意或忽略祖先 。
您可以指定处理行尾和空格更改的方式。这些选项在 “行尾和空格选项” 部分中描述。默认行为是将所有空格和行尾差异视为要合并的实际更改。
标记为 强制合并 的复选框用于避免树冲突,其中传入的删除会影响本地修改或根本未版本控制的文件。如果文件被删除,则无法恢复它,这就是默认情况下未选中该选项的原因。
标记为 允许混合修订版本(不推荐) 的复选框用于允许合并到混合修订版本工作副本(对应于命令行选项 --allow-mixed-revisions
)。自 Subversion 1.7 以来的默认设置是不允许合并到混合修订版本工作副本。原因在 Subversion 书籍中 “ 保持分支同步 ” 一节末尾进行了描述。如果您了解合并到混合修订版本工作副本可能存在的问题,您可以选中此复选框以继续执行合并。
如果您正在使用合并跟踪并且想要将修订版本标记为已合并,而实际上并未在此处执行合并,请选中 仅记录合并 复选框。您可能出于两个可能的原因想要这样做。可能是合并对于合并算法来说太复杂了,因此您手动编写更改代码,然后将更改标记为已合并,以便合并跟踪算法知道它。或者您可能想要阻止合并特定修订版本。将其标记为已合并将阻止合并跟踪感知客户端发生合并。
现在一切都设置好了,您要做的就是单击 不 会修改工作副本。它会向您显示将由实际合并更改的文件列表,并记录 可能 发生冲突的文件。由于合并跟踪使合并过程变得更加复杂,因此无法保证提前找出合并是否会在没有冲突的情况下完成,因此在测试合并中标记为冲突的文件实际上可能会在没有任何问题的情况下合并。
按钮。如果您想预览结果, 会模拟合并操作,但合并进度对话框显示合并的每个阶段,以及涉及的修订版本范围。这可能表示比您预期的多一个修订版本。例如,如果您要求合并修订版本 123,则进度对话框将报告 “ 合并修订版本 122 到 123 ”。要理解这一点,您需要记住合并与差异密切相关。合并过程的工作方式是生成存储库中两个点之间差异的列表,并将这些差异应用于您的工作副本。进度对话框只是显示差异的起点和终点。
合并现已完成。最好查看一下合并,看看它是否符合预期。合并通常非常复杂。如果分支偏离主干太远,则经常会出现冲突。
每当修订版本合并到工作副本时,TortoiseSVN 都会从所有合并的修订版本生成日志消息。这些消息可以从提交对话框中的
按钮获得。要自定义生成的消息,请在您的工作副本上设置相应的项目属性。请参阅 “合并日志消息模板” 部分
对于 1.5 之前的 Subversion 客户端和服务器,不存储合并信息,并且必须手动跟踪合并的修订版本。当您测试了更改并准备提交此修订版本时,您的提交日志消息应 始终 包括已在合并中移植的修订版本号。如果您想稍后应用另一次合并,您将需要知道您已合并的内容,因为您不想多次移植更改。有关此的更多信息,请参阅 Subversion 书籍中的 合并的最佳实践 。
如果您的服务器和所有客户端都在运行 Subversion 1.5 或更高版本,则合并跟踪工具将记录合并的修订版本,并避免多次合并修订版本。这使您的生活更加简单,因为您可以简单地每次合并整个修订版本范围,并且知道实际上只会合并新的修订版本。
分支管理非常重要。如果您想使此分支与主干保持同步,则应确保经常合并,以便分支和主干不会偏离太远。当然,您仍然应该避免重复合并更改,如上所述。
如果您刚刚将功能分支合并回主干,则主干现在包含所有新的功能代码,并且该分支已过时。如果需要,您现在可以从存储库中删除它。
Subversion 无法将文件与文件夹合并,反之亦然 - 只能将文件夹合并到文件夹,将文件合并到文件。如果您单击文件并打开合并对话框,则必须在该对话框中给出文件的路径。如果您选择文件夹并打开对话框,则必须为合并指定文件夹 URL。
Subversion 1.5 引入了合并跟踪功能。当您将更改从一个树合并到另一个树时,合并的修订版本号会被存储,并且此信息可以用于多种不同的目的。
您可以避免两次合并同一修订版本的危险(重复合并问题)。一旦修订版本被标记为已合并,未来包含该修订版本的合并范围将跳过它。
当您将分支合并回主干时,日志对话框可以将分支提交显示为主干日志的一部分,从而更好地跟踪更改。
当您从合并对话框中显示日志对话框时,已合并的修订版本以灰色显示。
当显示文件的 blame 信息时,您可以选择显示合并修订版本的原始作者,而不是执行合并的人员。
您可以通过将修订版本包含在已合并修订版本的列表中来将修订版本标记为 不合并,而无需实际执行合并。
合并跟踪信息由客户端在执行合并时存储在 svn:mergeinfo
属性中。当提交合并时,服务器将该信息存储在数据库中,当您请求合并、日志或 blame 信息时,服务器可以做出相应的响应。为了使系统正常工作,您必须确保服务器、存储库和所有客户端都已升级。早期的客户端不会存储 svn:mergeinfo
属性,早期的服务器也不会提供新客户端请求的信息。
从 Subversion 的 合并跟踪文档 中了解更多关于合并跟踪的信息。
冲突解决器对话框中的文本由 SVN 库提供,因此可能(尚未)像 TortoiseSVN 对话框那样被翻译。对此表示抱歉。
合并并非总是顺利进行。有时会发生冲突。TortoiseSVN 通过显示 合并冲突 对话框来帮助您完成此过程。
很可能某些更改已顺利合并,而其他本地更改与已提交到存储库的更改冲突。所有可以合并的更改都已合并。合并冲突对话框为您提供了处理冲突行的不同方法。
对于由于文件内容或其属性更改而发生的正常冲突,对话框会显示按钮,允许您选择保留或拒绝冲突部分中的哪一部分。
现在不处理冲突。让合并继续,并在合并完成后解决冲突。
这使文件保持原样,既没有来自合并的更改,也没有您在工作副本中所做的更改。
这将丢弃所有本地更改,并使用来自合并源的文件。
这将丢弃来自合并源的所有更改,并保留包含本地编辑的文件。
这将丢弃您的本地更改,如果它们与来自合并源的更改冲突。但它会保留所有不冲突的本地更改。
这将丢弃来自合并源的更改,如果它们与您的本地更改冲突。但它会保留所有与本地更改不冲突的更改。
将冲突标记为已解决。此按钮在您使用
按钮手动编辑冲突并将这些更改保存回文件之前处于禁用状态。保存更改后,该按钮将变为启用状态。启动合并编辑器,以便您可以手动解决冲突。不要忘记保存文件,以便
按钮变为启用状态。
如果存在树冲突,请首先参阅 “树冲突” 部分,了解各种类型的树冲突以及它们如何以及为何会发生。
要解决合并后的树冲突,将显示一个对话框,其中包含有关如何解决冲突的各种选项
由于存在各种可能的树冲突情况,对话框将显示按钮以解决这些冲突,具体取决于特定冲突。按钮文本和标签解释了解决冲突的选项的作用。如果您不确定,请取消对话框或使用 按钮稍后解决冲突。
当您在单独的分支上开发新功能时,最好制定一个策略,以便在功能完成后重新集成。如果在 主干
中同时进行其他工作,您可能会发现差异随着时间的推移变得显着,并且合并回变得像一场噩梦。
如果功能相对简单且开发时间不长,那么您可以采用一种简单的方法,即在功能完成之前将分支完全分离,然后将分支更改合并回主干。在合并向导中,这将是一个简单的 合并修订版本范围,修订版本范围是分支的修订版本跨度。
如果功能需要更长时间,并且您需要考虑 主干
中的更改,那么您需要保持分支同步。这仅仅意味着您定期将主干更改合并到分支中,以便分支包含所有主干更改 以及 新功能。同步过程使用 合并修订版本范围。当功能完成后,您可以使用 重新集成分支 或 合并两个不同的树 将其合并回 主干
。
将所有更改从主干合并到功能分支的另一种(快速)方法是使用扩展上下文菜单中的 Shift 键,同时右键单击文件)。
→ (按住
此对话框非常容易。您要做的就是设置合并的选项,如 “合并选项” 部分所述。其余的由 TortoiseSVN 使用合并跟踪自动完成。