本文档尚在编写中——内容可能发生重大变化——可能无法准确描述 Apache™ Subversion® 软件的任何已发布版本。将此页面添加书签或以其他方式向他人推荐此页面可能不是一个明智的做法。请访问 https://svnbook.subversion.org.cn/ 以获取此书的稳定版本。

使用外部差异和合并工具

Subversion 与外部双向和三向差异工具之间的接口可以追溯到 Subversion 唯一基于上下文的差异功能都围绕着 GNU diffutils 工具链的调用,特别是 diffdiff3 实用程序。为了获得 Subversion 所需的行为,它会调用这些实用程序,并提供大量选项和参数,其中大多数参数非常具体。一段时间后,Subversion 开发了自己的内部差异库,并且作为一种故障转移机制,--diff-cmd--diff3-cmd 选项被添加到 Subversion 命令行客户端,以便用户可以更轻松地表明他们更喜欢使用 GNU diff 和 diff3 实用程序,而不是新的内部差异库。如果使用这些选项,Subversion 将简单地忽略内部差异库,并回退到运行这些外部程序,以及所有冗长的参数列表。这就是今天的情况。

人们很快就意识到,对于指定 Subversion 应该使用系统特定位置的外部 GNU diff 和 diff3 实用程序,拥有如此简单的配置机制也可以应用于其他差异工具。毕竟,Subversion 并没有实际验证它被告知要运行的程序是否是 GNU diffutils 工具链的成员。但是,使用这些外部工具的唯一可配置方面是它们在系统中的位置——而不是选项集、参数顺序等等。无论该程序是否能够理解这些选项,Subversion 都会将所有这些 GNU 实用程序选项传递给您的外部 diff 工具。这就是对大多数用户来说不直观的地方。

[Note] 注意

关于何时在更大型的 Subversion 操作中触发基于上下文的双向或三向 diff 的决定是由 Subversion 在内部做出的,并受以下因素影响,包括但不限于正在操作的文件是否可以被人类读取(如由它们的 svn:mime-type 属性决定)。这意味着,例如,即使您拥有宇宙中最棒的 Microsoft Word 感知差异或合并工具,如果您的版本化 Word 文档配置了表示它们不可读的 MIME 类型(例如 application/msword),Subversion 通常不会调用它。幸运的是,您可以将 --force 选项传递给 svn diff 以绕过此 MIME 相关的健全性检查,并强制计算差异。有关 MIME 类型设置的更多信息,请参阅 名为“文件内容类型”的部分

后来,Subversion 1.5 引入了交互式冲突解决(在 名为“解决所有冲突”的部分 中描述)。此功能为用户提供的选项之一是能够交互式地启动第三方合并工具。如果采取此操作,Subversion 将检查用户是否已为此方式指定了这样的工具。Subversion 将首先检查 SVN_MERGE 环境变量以获取外部合并工具的名称。如果未设置该变量,它将查找 merge-tool-cmd 运行时配置选项的值中的相同信息。找到配置的外部合并工具后,它将调用该工具。

[Note] 注意

虽然三向差异和合并工具的总体目的大致相同(找到一种方法使分离但重叠的文件更改和谐共处),但 Subversion 在不同的时间和出于不同的原因使用这些选项中的每一个。内部三向差异引擎及其可选的外部替换在不需要与用户交互时使用。事实上,由这种工具引入的重大延迟实际上会导致某些时间敏感的 Subversion 操作失败。外部合并工具旨在交互式调用。

现在,虽然 Subversion 与外部合并工具之间的接口比 Subversion 与 diff 和 diff3 工具之间的接口简单得多,但找到调用约定完全符合 Subversion 预期的工具的可能性仍然很低。使用外部差异和合并工具与 Subversion 的关键是使用包装器脚本,这些脚本将来自 Subversion 的输入转换为您的特定差异工具可以理解的内容,然后将您工具的输出转换回 Subversion 预期的格式。以下部分将介绍这些期望的具体内容。

外部 diff

Subversion 使用适合 GNU diff 实用程序的参数调用外部 diff 程序,并且仅期望外部程序按照 GNU diff 的定义返回成功错误代码。对于大多数替代 diff 程序,只有第六和第七个参数——表示 diff 的左右两侧的两个文件的路径——是感兴趣的。请注意,Subversion 为 Subversion 操作覆盖的每个修改文件运行 diff 程序一次,因此,如果您的程序以异步方式运行(或被 后台化),您可能会有多个实例同时运行。最后,Subversion 期望您的程序返回错误代码 1(如果您的程序检测到差异)或 0(如果未检测到差异)——任何其他错误代码都被视为致命错误。 [76]

示例 7.2,“diffwrap.py”示例 7.3,“diffwrap.bat” 分别是 Python 和 Windows 批处理脚本语言中外部 diff 工具包装器的模板。

示例 7.2。diffwrap.py

#!/usr/bin/env python
import sys
import os

# Configure your favorite diff program here.
DIFF = "/usr/local/bin/my-diff-tool"

# Subversion provides the paths we need as the last two parameters.
LEFT  = sys.argv[-2]
RIGHT = sys.argv[-1]

# Call the diff command (change the following line to make sense for
# your diff program).
cmd = [DIFF, '--left', LEFT, '--right', RIGHT]
os.execv(cmd[0], cmd)

# Return an errorcode of 0 if no differences were detected, 1 if some were.
# Any other errorcode will be treated as fatal.

示例 7.3。diffwrap.bat

@ECHO OFF

REM Configure your favorite diff program here.
SET DIFF="C:\Program Files\Funky Stuff\My Diff Tool.exe"

REM Subversion provides the paths we need as the last two parameters.
REM These are parameters 6 and 7 (unless you use svn diff -x, in
REM which case, all bets are off).
SET LEFT=%6
SET RIGHT=%7

REM Call the diff command (change the following line to make sense for
REM your diff program).
%DIFF% --left %LEFT% --right %RIGHT%

REM Return an errorcode of 0 if no differences were detected, 1 if some were.
REM Any other errorcode will be treated as fatal.

外部 diff3

Subversion 调用三向差异程序以执行非交互式合并。当配置为使用外部三向差异程序时,它会使用适合 GNU diff3 实用程序的参数执行该程序,期望外部程序返回成功错误代码,并且合并操作完成后产生的完整文件内容将打印在标准输出流上(以便 Subversion 可以将它们重定向到适当的版本控制文件中)。对于大多数替代合并程序,只有第九、第十和第十一个参数——表示 mineolderyours 输入的三个文件的路径——是感兴趣的。请注意,因为 Subversion 依赖于您的合并程序的输出,所以您的包装器脚本在将该输出传递给 Subversion 之前不得退出。当它最终退出时,它应该返回错误代码 0(如果合并成功)或 1(如果输出中仍存在未解决的冲突)——任何其他错误代码都被视为致命错误。

示例 7.4,“diff3wrap.py”示例 7.5,“diff3wrap.bat” 分别是 Python 和 Windows 批处理脚本语言中外部三向差异工具包装器的模板。

示例 7.4。diff3wrap.py

#!/usr/bin/env python
import sys
import os

# Configure your favorite three-way diff program here.
DIFF3 = "/usr/local/bin/my-diff3-tool"

# Subversion provides the paths we need as the last three parameters.
MINE  = sys.argv[-3]
OLDER = sys.argv[-2]
YOURS = sys.argv[-1]

# Call the three-way diff command (change the following line to make
# sense for your three-way diff program).
cmd = [DIFF3, '--older', OLDER, '--mine', MINE, '--yours', YOURS]
os.execv(cmd[0], cmd)

# After performing the merge, this script needs to print the contents
# of the merged file to stdout.  Do that in whatever way you see fit.
# Return an errorcode of 0 on successful merge, 1 if unresolved conflicts
# remain in the result.  Any other errorcode will be treated as fatal.

示例 7.5。diff3wrap.bat

@ECHO OFF

REM Configure your favorite three-way diff program here.
SET DIFF3="C:\Program Files\Funky Stuff\My Diff3 Tool.exe"

REM Subversion provides the paths we need as the last three parameters.
REM These are parameters 9, 10, and 11.  But we have access to only
REM nine parameters at a time, so we shift our nine-parameter window
REM twice to let us get to what we need.
SHIFT
SHIFT
SET MINE=%7
SET OLDER=%8
SET YOURS=%9

REM Call the three-way diff command (change the following line to make
REM sense for your three-way diff program).
%DIFF3% --older %OLDER% --mine %MINE% --yours %YOURS%

REM After performing the merge, this script needs to print the contents
REM of the merged file to stdout.  Do that in whatever way you see fit.
REM Return an errorcode of 0 on successful merge, 1 if unresolved conflicts
REM remain in the result.  Any other errorcode will be treated as fatal.

外部合并

Subversion 可选地调用外部合并工具作为其对交互式冲突解决的支持的一部分。它向合并工具提供以下参数:未修改的基线文件的路径、theirs 文件的路径(包含上游更改)、mine 文件的路径(包含本地修改)、合并工具应将最终解决的內容存储到的文件的路径以及冲突文件的 工作副本路径(相对于合并操作的原始目标)。合并工具应返回错误代码 0 以指示成功,或 1 以指示失败。

示例 7.6,“mergewrap.py”示例 7.7,“mergewrap.bat” 分别是 Python 和 Windows 批处理脚本语言中外部合并工具包装器的模板。

示例 7.6。mergewrap.py

#!/usr/bin/env python
import sys
import os

# Configure your favorite merge program here.
MERGE = "/usr/local/bin/my-merge-tool"

# Get the paths provided by Subversion.
BASE   = sys.argv[1]
THEIRS = sys.argv[2]
MINE   = sys.argv[3]
MERGED = sys.argv[4]
WCPATH = sys.argv[5]

# Call the merge command (change the following line to make sense for
# your merge program).
cmd = [MERGE, '--base', BASE, '--mine', MINE, '--theirs', THEIRS,
              '--outfile', MERGED]
os.execv(cmd[0], cmd)

# Return an errorcode of 0 if the conflict was resolved; 1 otherwise.
# Any other errorcode will be treated as fatal.

示例 7.7。mergewrap.bat

@ECHO OFF

REM Configure your favorite merge program here.
SET MERGE="C:\Program Files\Funky Stuff\My Merge Tool.exe"

REM Get the paths provided by Subversion.
SET BASE=%1
SET THEIRS=%2
SET MINE=%3
SET MERGED=%4
SET WCPATH=%5

REM Call the merge command (change the following line to make sense for
REM your merge program).
%MERGE% --base %BASE% --mine %MINE% --theirs %THEIRS% --outfile %MERGED%

REM Return an errorcode of 0 if the conflict was resolved; 1 otherwise.
REM Any other errorcode will be treated as fatal.



[76] GNU diff 手册页是这样说的:退出状态为 0 表示未发现差异,1 表示发现了一些差异,2 表示出现问题。

TortoiseSVN 官方中文版 1.14.7 发布