本文档仍在编写中,内容可能会发生很大变化,可能无法准确描述 Apache™ Subversion® 软件的任何发布版本。将此页面添加为书签或以其他方式将此页面推荐给其他人可能不是一个好主意。请访问 https://svnbooks.subversion.org.cn/ 获取本书的稳定版本。

基本工作循环

Subversion 拥有众多功能、选项、铃铛和哨子,但在日常工作中,你很有可能只使用其中的一小部分。在本节中,我们将介绍在一天的工作中可能需要使用 Subversion 执行的最常见操作。

典型的工作循环如下所示

  1. 更新您的工作副本。 这涉及使用 svn update 命令。

  2. 进行更改。 您将进行的最常见更改是对现有文件内容的编辑。但有时您需要添加、删除、复制和移动文件和目录 - svn addsvn deletesvn copysvn move 命令处理工作副本中的这些结构性更改。

  3. 查看您的更改。 svn statussvn diff 命令对于查看您在工作副本中所做的更改至关重要。

  4. 修复您的错误。 没有人是完美的,因此在查看您的更改时,您可能会发现一些不正确的地方。有时,修复错误的最简单方法是从头开始。 svn revert 命令将文件或目录恢复到未修改状态。

  5. 解决任何冲突(合并他人的更改)。 在您进行和查看更改所需的时间内,其他人可能也已经进行了更改并发布了更改。您需要将他们的更改集成到您的工作副本中,以避免在尝试发布您自己的更改时可能出现的过时情况。同样,svn update 命令是执行此操作的方法。如果这导致本地冲突,您需要使用 svn resolve 命令解决这些冲突。

  6. 发布(提交)您的更改。 svn commit 命令将您的更改传输到存储库,如果它们被接受,它们将创建您修改的所有事物的最新版本。现在其他人也可以看到您的工作了!

更新您的工作副本

当处理一个通过多个工作副本进行修改的项目时,您需要更新您的工作副本,以便接收自您上次更新以来从其他工作副本提交的任何更改。这些可能是您的项目团队其他成员所做的更改,也可能是您自己从另一台计算机所做的更改。为了保护您的数据,Subversion 不会允许您将新的更改提交到过时的文件和目录,因此最好在进行您自己的新更改之前拥有项目所有文件和目录的最新版本。

使用 svn update 将您的工作副本与存储库中的最新修订版同步

$ svn update
Updating '.':
U    foo.c
U    bar.c
Updated to revision 2.
$

在这种情况下,似乎有人自您上次更新以来对 foo.cbar.c 都进行了修改,并且 Subversion 已更新您的工作副本以包含这些更改。

当服务器通过 svn update 将更改发送到您的工作副本时,将在每个项目旁边显示一个字母代码,以让您知道 Subversion 为使您的工作副本保持最新而执行了哪些操作。要了解这些字母的含义,请运行 svn help update 或查看 svn update (up)svn 参考 - Subversion 命令行客户端 中。

进行更改

现在您可以开始工作,并在您的工作副本中进行更改。您可以对工作副本进行两种更改:文件更改树更改。您无需告诉 Subversion 您打算更改文件;只需使用您的文本编辑器、文字处理器、图形程序或您通常使用的任何工具进行更改即可。Subversion 会自动检测哪些文件已更改,此外,它会像处理文本文件一样轻松高效地处理二进制文件。树更改不同,涉及对目录结构的更改。此类更改包括添加和删除文件、重命名文件或目录以及将文件或目录复制到新位置。对于树更改,您使用 Subversion 操作来 计划 文件和目录以进行删除、添加、复制或移动。这些更改可能会立即在您的工作副本中发生,但直到您提交更改后,存储库中才会发生任何添加或删除。

以下是您最常用来进行树更改的五个 Subversion 子命令的概述

svn add FOO

使用此命令计划将文件、目录或符号链接 FOO 添加到存储库。在您下次提交时,FOO 将成为其父目录的子目录。请注意,如果 FOO 是一个目录,则 FOO 下的所有内容都将被计划添加。如果您只想添加 FOO 本身,请传递 --depth=empty 选项。

svn delete FOO

使用此命令计划将文件、目录或符号链接 FOO 从存储库中删除。 FOO 会立即从您的工作副本中删除。(当然,存储库中没有任何东西被完全删除 - 只是从其 HEAD 修订版中删除。您仍然可以访问先前修订版中的已删除项目)。[6]

svn copy FOO BAR

创建一个名为 BAR 的新项目,作为 FOO 的副本,并自动计划将 BAR 添加。当 BAR 在下次提交时被添加到存储库时,其复制历史记录将被记录(最初来自 FOO)。svn copy 不会创建中间目录,除非您传递 --parents 选项。

svn move FOO BAR

此命令与运行 svn copy FOO BAR; svn delete FOO 完全相同。也就是说,BAR 被计划添加为 FOO 的副本,而 FOO 被计划删除。svn move 不会创建中间目录,除非您传递 --parents 选项。

svn mkdir FOO

此命令与运行 mkdir FOO; svn add FOO 完全相同。也就是说,将创建一个名为 FOO 的新目录并计划将其添加。

查看您的更改

完成更改后,您需要将它们提交到存储库,但在您这样做之前,通常最好查看一下您到底更改了什么。通过在提交之前检查更改,您可以撰写更准确的 日志消息(存储库中存储在这些更改旁边的更改的人类可读描述)。您也可能发现您无意中更改了一个文件,并且需要在提交之前撤消该更改。此外,这是一个在发布更改之前查看和仔细检查更改的好机会。您可以使用 svn status 命令查看您所做更改的概述,并且可以使用 svn diff 命令深入了解这些更改的详细信息。

查看更改概述

要获得更改的概述,请使用svn status命令。您可能比任何其他 Subversion 命令都更频繁地使用svn status

[Tip] 提示

由于cvs status命令的输出非常冗长,并且由于cvs update不仅执行更新,还报告本地更改的状态,因此大多数 CVS 用户已习惯使用cvs update来报告他们的更改。在 Subversion 中,更新和状态报告功能是完全独立的。请参阅名为“Status 和 Update 之间的区别”部分以获取更多详细信息。

如果您在工作副本的顶部运行svn status,且没有其他参数,它将检测并报告您所做的所有文件和树更改。

$ svn status
?       scratch.c
A       stuff/loot
A       stuff/loot/new.c
D       stuff/old.c
M       bar.c
$

在默认输出模式下,svn status 打印七列字符,然后是几个空格,最后是文件或目录名称。第一列显示文件或目录及其内容的状态。svn status 显示的一些最常见的代码是

? item

文件、目录或符号链接item 不在版本控制之下。

A item

文件、目录或符号链接item 已安排添加到存储库中。

C item

文件item 处于冲突状态。也就是说,从服务器接收的更改在更新过程中与您工作副本中的本地更改发生冲突(并且在更新过程中未解决)。您必须在将更改提交到存储库之前解决此冲突。

D item

文件、目录或符号链接item 已安排从存储库中删除。

M item

文件item 的内容已修改。

如果您将特定路径传递给svn status,您将获得有关该项目单独的信息

$ svn status stuff/fish.c
D       stuff/fish.c

svn status 还有一个--verbose (-v) 选项,它将显示工作副本中每个项目的状况,即使它没有更改

$ svn status -v
M               44        23    sally     README
                44        30    sally     INSTALL
M               44        20    harry     bar.c
                44        18    ira       stuff
                44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
                44        21    sally     stuff/things
A                0         ?     ?        stuff/things/bloo.h
                44        36    harry     stuff/things/gloo.c

这是svn status长格式 输出。第一列中的字母与之前相同,但第二列显示项目的当前版本。第三列和第四列显示项目最后一次更改的版本以及更改它的人员。

所有先前的svn status 调用都不会联系存储库——它们仅根据存储在工作副本管理区域中的记录以及修改文件的日期戳和内容报告有关工作副本项目的信息。但是,有时查看工作副本中的哪些项目自上次更新工作副本以来在存储库中已修改是有用的。为此,svn status 提供了--show-updates (-u) 选项,该选项会联系存储库并添加有关已过时项目的信息

$ svn status -u -v
M      *        44        23    sally     README
M               44        20    harry     bar.c
       *        44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
A                0         ?     ?        stuff/things/bloo.h
Status against revision:   46

请注意上例中的两个星号:如果您此时运行svn update,您将收到对READMEtrout.c 的更改。这告诉您一些非常有用的信息——因为其中一项也是您在本地修改过的项目(文件README),您需要更新并获取该文件的服务器更改,然后才能提交,否则存储库会因为过时而拒绝您的提交。我们将在后面详细讨论这一点。

svn status 可以显示有关工作副本中文件和目录的更多信息,而不是我们在这里展示的信息——有关svn status 及其输出的详细描述,请运行svn help status 或参阅svn status (stat, st) in svn 参考——Subversion 命令行客户端

检查本地修改的详细信息

另一种检查更改的方法是使用svn diff 命令,该命令显示文件内容的差异。当您在工作副本的顶部运行svn diff 且没有参数时,Subversion 将打印您在工作副本中对人类可读文件所做的更改。它以统一 diff 格式显示这些更改,该格式将更改描述为文件内容的(或片段),其中每行文本都以一个单字符代码作为前缀:空格,表示该行未更改;减号 (-),表示该行已从文件中删除;或加号 (+),表示该行已添加到文件中。在svn diff 的上下文中,那些以减号和加号为前缀的代码分别显示了您修改前后的代码行。

以下是一个示例

$ svn diff
Index: bar.c
===================================================================
--- bar.c	(revision 3)
+++ bar.c	(working copy)
@@ -1,7 +1,12 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>

 int main(void) {
-  printf("Sixty-four slices of American Cheese...\n");
+  printf("Sixty-five slices of American Cheese...\n");
 return 0;
 }

Index: README
===================================================================
--- README	(revision 3)
+++ README	(working copy)
@@ -193,3 +193,4 @@
+Note to self:  pick up laundry.

Index: stuff/fish.c
===================================================================
--- stuff/fish.c	(revision 1)
+++ stuff/fish.c	(working copy)
-Welcome to the file known as 'fish'.
-Information on fish will be here soon.

Index: stuff/things/bloo.h
===================================================================
--- stuff/things/bloo.h	(revision 8)
+++ stuff/things/bloo.h	(working copy)
+Here is a new file to describe
+things about bloo.

svn diff 命令通过将您的工作文件与原始的 text-base 进行比较来生成此输出。计划添加的文件显示为每个代码行都被添加的文件;计划删除的文件显示为每个代码行都已从这些文件中删除。来自svn diff 的输出与patch 程序略有兼容——与 Subversion 1.7 中引入的svn patch 子命令更兼容。像这些的补丁处理命令读取并应用补丁文件(或补丁),这些文件描述对一个或多个文件所做的更改。因此,您可以通过从svn diff 的重定向输出创建补丁文件,与他人共享您在工作副本中所做的更改,而无需先提交这些更改

$ svn diff > patchfile
$

默认情况下,Subversion 使用其内部 diff 引擎,该引擎生成统一 diff 格式。如果您希望以其他格式获得 diff 输出,请使用--diff-cmd 指定外部 diff 程序,并通过--extensions (-x) 选项传递其需要的任何其他标志。例如,您可能希望 Subversion 延迟其差异计算并显示给 GNUdiff 程序,并要求该程序在上下文 diff 格式(另一种差异格式)中打印对文件foo.c 所做的本地修改,同时忽略仅对文件内容中使用的字母的大小写所做的更改

$ svn diff --diff-cmd /usr/bin/diff -x "-i" foo.c
…
$

修复错误

假设在查看svn diff 的输出时,您发现您对特定文件所做的所有更改都是错误的。也许您根本不应该更改该文件,或者也许从头开始进行不同的更改会更容易。您可以再次编辑该文件并撤消所有这些更改。您可以尝试找到您更改该文件之前的副本,然后将它的内容复制到您的修改版本之上。您可以尝试使用svn patch --reverse-diff 或使用操作系统的patch -R 以相反的方式将这些更改应用到该文件。并且您可能还会采用其他方法。

幸运的是,在 Subversion 中,撤消您的工作并从头开始并不需要这种杂技表演。只需使用svn revert 命令即可

$ svn status README
M       README
$ svn revert README
Reverted 'README'
$ svn status README
$

在此示例中,Subversion 通过用缓存的 text-base 区域中的原始版本覆盖文件,将其恢复到修改前的状态。但请注意,svn revert 可以撤消任何计划的操作——例如,您可能决定您不想添加新文件

$ svn status new-file.txt
?       new-file.txt
$ svn add new-file.txt
A         new-file.txt
$ svn revert new-file.txt
Reverted 'new-file.txt'
$ svn status new-file.txt
?       new-file.txt
$

或者,也许您错误地从版本控制中删除了一个文件

$ svn status README
$ svn delete README
D         README
$ svn revert README
Reverted 'README'
$ svn status README
$

svn revert 命令为不完美的人提供了救赎。它可以为您节省大量的时间和精力,这些时间和精力原本会花费在手动撤消更改上,或者更糟糕的是,丢弃您的工作副本并签出新的副本,只是为了获得一个干净的画布再次使用。

解决任何冲突

我们已经看到svn status -u 如何预测冲突,但处理这些冲突仍然需要完成。任何时候您尝试将存储库中的更改合并或集成(从非常通用的意义上讲)到您的工作副本中,都会发生冲突。到目前为止,您已经知道svn update 会创建这种场景——该命令的真正目的是通过将自上次更新以来所做的所有更改合并到您的工作副本中,使您的工作副本与存储库保持同步。那么,Subversion 如何向您报告这些冲突,以及如何处理它们呢?

假设您运行svn update,并且您看到了这种有趣的输出

$ svn update
Updating '.':
U    INSTALL
G    README
Conflict discovered in 'bar.c'.
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options:
        

U(代表已更新)和G(代表已合并)代码没有引起任何问题;这些文件干净地吸收了来自存储库的更改。标记为U 的文件不包含任何本地更改,但已使用来自存储库的更改进行了更新。标记为G 的文件最初包含本地更改,但来自存储库的更改与这些本地更改没有冲突。

接下来的几行很有趣。首先,Subversion 向您报告,在尝试将未完成的服务器更改合并到文件bar.c 中时,它检测到其中一些更改与您在工作副本中所做的本地修改发生冲突,但尚未提交。也许有人更改了您也更改的同一行文本。无论原因是什么,Subversion 都立即将此文件标记为处于冲突状态。然后它会询问您想对这个问题做些什么,允许您交互式地选择对解决冲突采取的措施。最常用的选项将显示出来,但您可以通过键入s 来查看所有选项

…
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: s

  (e)  - change merged file in an editor  [edit]
  (df) - show all changes made to merged file
  (r)  - accept merged version of file

  (dc) - show all conflicts (ignoring merged version)
  (mc) - accept my version for all conflicts (same)  [mine-conflict]
  (tc) - accept their version for all conflicts (same)  [theirs-conflict]

  (mf) - accept my version of entire file (even non-conflicts)  [mine-full]
  (tf) - accept their version of entire file (same)  [theirs-full]

  (m)  - use internal merge tool to resolve conflict
  (l)  - launch external tool to resolve conflict  [launch]
  (p)  - mark the conflict to be resolved later  [postpone]
  (q)  - postpone all remaining conflicts
  (s)  - show this list (also 'h', '?')
Words in square brackets are the corresponding --accept option arguments.

Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options:

在我们详细介绍每个选项的含义之前,让我们简要回顾一下每个选项。

(e) edit [编辑]

使用您在环境变量 EDITOR 中设置的喜爱的编辑器打开与之冲突的文件。

(df) diff-full

以统一 diff 格式显示基本修订版与冲突文件本身之间的差异。

(r) resolved

编辑文件后,告诉 svn 您已解决文件中的冲突,并且它应该接受当前内容 - 基本上,您已 解决 冲突。

(dc) display-conflict

显示文件的所有冲突区域,忽略已成功合并的更改。

(mc) mine-conflict [mine-conflict]

丢弃来自服务器的任何新接收的更改,这些更改与您对所审阅文件的本地更改冲突。但是,接受并合并从服务器接收到的该文件的任何非冲突更改。

(tc) theirs-conflict [theirs-conflict]

丢弃与来自服务器的传入更改冲突的任何本地更改,这些更改针对所审阅的文件。但是,保留对该文件的所有非冲突本地更改。

(mf) mine-full [mine-full]

丢弃来自服务器的针对所审阅文件的所有新接收的更改,但保留对该文件的所有本地更改。

(tf) theirs-full [theirs-full]

丢弃您对所审阅文件的所有本地更改,并仅使用来自服务器的针对该文件的新接收的更改。

(m) merge

启动内部文件合并工具以执行冲突解决。该选项从 Subversion 1.8 开始可用。

(l) launch

启动外部程序以执行冲突解决。这需要事先进行一些准备。

(p) postpone [postpone]

将文件保留在冲突状态,以便您在更新完成后解决。

(s) show all

显示您可以在交互式冲突解决中使用的所有可能命令的列表。

我们现在将更详细地介绍这些命令,并将它们按相关功能进行分组。

以交互方式查看冲突差异

在决定如何以交互方式解决冲突之前,您很可能希望确切了解冲突的内容。交互式冲突解决提示中提供的两个命令可以帮助您解决此问题。第一个是 diff-full 命令 (df),它将显示对所述文件的本地修改以及任何冲突区域。

…
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: df
--- .svn/text-base/sandwich.txt.svn-base      Tue Dec 11 21:33:57 2007
+++ .svn/tmp/tempfile.32.tmp     Tue Dec 11 21:34:33 2007
@@ -1 +1,5 @@
-Just buy a sandwich.
+<<<<<<< .mine
+Go pick up a cheesesteak.
+=======
+Bring me a taco!
+>>>>>>> .r32
…

diff 内容的第一行显示工作副本的先前内容(BASE 修订版),下一行内容是您的更改,最后一行内容是从服务器接收到的更改(通常HEAD 修订版)。

第二个命令类似于第一个命令,但 display-conflict (dc) 命令仅显示冲突区域,而不显示对文件所做的所有更改。此外,此命令使用略微不同的冲突区域显示格式,使您能够更轻松地比较这些区域中文件的显示内容,就像它们出现在三种状态中一样:原始且未编辑;应用您的本地更改并忽略服务器的冲突更改;以及仅应用服务器的传入更改并还原您的本地冲突更改。

查看完这些命令提供的信息后,您可以继续执行下一步操作。

以交互方式解决冲突差异

以交互方式解决冲突的主要方法是使用内部文件合并工具。该工具会询问您如何处理每个冲突更改,并允许您有选择地合并和编辑更改。但是,还有几种其他不同的方式可以以交互方式解决冲突 - 其中两种允许您使用外部编辑器有选择地合并和编辑更改,而其余方法允许您简单地选择一个文件版本并继续。内部合并工具将所有可用的冲突解决方法结合在一起。

您已经查看了冲突的更改,因此现在是时候解决冲突了。第一个可以帮助您的命令是 merge 命令 (m),该命令从 Subversion 1.8 开始可用。该命令会显示冲突区域,并允许您从多个选项中选择以逐个区域地解决冲突。

Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: m
Merging 'Makefile'.
Conflicting section found during merge:
(1) their version (at line 24)                  |(2) your version (at line 24)
------------------------------------------------+------------------------------------------------
top_builddir = /bar                             |top_builddir = /foo
------------------------------------------------+------------------------------------------------
Select: (1) use their version, (2) use your version,
        (12) their version first, then yours,
        (21) your version first, then theirs,
        (e1) edit their version and use the result,
        (e2) edit your version and use the result,
        (eb) edit both versions and use the result,
        (p) postpone this conflicting section leaving conflict markers,
        (a) abort file merge and return to main menu:

如您所见,当您使用内部文件合并工具时,您可以遍历文件中的各个冲突区域,并选择各种解决选项或推迟对选定冲突的冲突解决。

但是,如果您希望使用外部编辑器选择本地更改的组合,则可以使用 edit 命令 (e) 在文本编辑器中手动编辑带有冲突标记的文件(根据 名为“使用外部编辑器”的部分中的说明进行配置)。编辑完文件后,如果您对所做的更改感到满意,则可以使用 resolved 命令 (r) 告诉 Subversion 编辑后的文件不再处于冲突状态。

无论您当地的 Unix 狂热分子可能告诉您什么,在您最喜欢的文本编辑器中手动编辑文件都是一种相当低技术的方法来弥补冲突(请参阅 名为“手动冲突解决”的部分,以获取操作指南)。为此,Subversion 提供了 launch 解决命令 (l) 以启动一个花哨的图形合并工具(请参阅 名为“外部合并”的部分)。

此外,还提供了两个折衷选项。mine-conflict (mc) 和 theirs-conflict (tc) 命令分别指示 Subversion 选择您的本地更改或服务器的传入更改作为文件中所有冲突的 获胜者。但与 mine-fulltheirs-full 命令不同,这些命令会保留您的本地更改以及从服务器接收到的更改,这些更改位于未检测到冲突的文件区域。

最后,如果您决定不需要合并任何更改,而只是想要接受文件的一个版本或另一个版本,则可以使用 mine-full 命令 (mf) 选择您的更改(又名 mine),或使用 theirs-full 命令 (tf) 选择他们的更改。

推迟冲突解决

这听起来像是避免婚姻分歧的适当部分,但实际上仍然与 Subversion 有关,所以请继续阅读。如果您正在进行更新并且遇到了您没有准备审查或解决的冲突,则可以在运行 svn update 时输入 p 以推迟对文件的冲突解决。如果您事先知道您不想以交互方式解决任何冲突,则可以将 --non-interactive 选项传递给 svn update,并且任何冲突文件都会自动标记为 C

从 Subversion 1.8 开始,内部文件合并工具允许您推迟对某些冲突的冲突解决,但解决其他冲突。因此,您可以逐个区域地推迟冲突解决,而不仅仅是在文件到文件的基础上。

C(表示 Conflicted)表示服务器中的更改与您自己的更改重叠,现在您必须在更新完成后手动选择它们。当您推迟冲突解决时,svn 通常会执行三项操作来帮助您注意到和解决冲突。

  • Subversion 在更新期间打印一个 C 并记住该文件处于冲突状态。

  • 如果 Subversion 认为该文件是可合并的,它会在文件中放置 冲突标记 - 用于分隔冲突 方面 的特殊文本字符串 - 以直观地展示重叠的区域。(Subversion 使用 svn:mime-type 属性来决定文件是否能够进行基于上下文的行合并。请参阅 名为“文件内容类型”的部分以了解更多信息。)

  • 对于每个冲突文件,Subversion 都会在您的工作副本中放置三个额外的未版本化文件。

    filename.mine

    这是文件在您开始更新过程之前在工作副本中存在的样子。它包含您在该点之前对文件所做的所有本地修改。(如果 Subversion 认为该文件不可合并,则不会创建 .mine 文件,因为它与工作文件相同。)

    filename.rOLDREV

    这是文件在 BASE 修订版中存在的样子 - 即,您在开始更新过程 之前 在工作副本中未修改的文件修订版 - 其中 OLDREV 是该基本修订版号。

    filename.rNEWREV

    这是您的 Subversion 客户端刚刚通过更新工作副本从服务器接收到的文件,其中 NEWREV 对应于您正在更新的修订版号(HEAD,除非另有要求)。

例如,Sally 对文件 sandwich.txt 进行更改,但尚未提交这些更改。与此同时,Harry 提交了对同一文件的更改。Sally 在提交之前更新了她的工作副本,并且她遇到了冲突,她推迟了该冲突。

$ svn update
Updating '.':
Conflict discovered in 'sandwich.txt'.
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: p
C    sandwich.txt
Updated to revision 2.
Summary of conflicts:
  Text conflicts: 1
$ ls -1
sandwich.txt
sandwich.txt.mine
sandwich.txt.r1
sandwich.txt.r2

此时,Subversion 不会 允许 Sally 提交文件 sandwich.txt,直到删除三个临时文件。

$ svn commit -m "Add a few more things"
svn: E155015: Commit failed (details follow):
svn: E155015: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict

如果您推迟了冲突,则需要在 Subversion 允许您提交更改之前解决冲突。您将使用 svn resolve 命令执行此操作。此命令接受 --accept 选项,该选项允许您指定解决冲突的所需方法。在 Subversion 1.8 之前,svn resolve 命令 需要 使用此选项。Subversion 现在允许您运行 svn resolve 命令而不使用该选项。当您这样做时,Subversion 会启动其交互式冲突解决机制,您可以在上一节 名为“以交互方式解决冲突差异”的部分中阅读(如果您尚未阅读)。不过,我们将在本节中借此机会讨论使用 --accept 选项进行冲突解决。

svn resolve 命令中使用 --accept 选项可以指示 Subversion 使用其预定义的冲突解决方法之一。如果要让 Subversion 使用您最后一次检出文件时的版本来解决冲突(在进行编辑之前),请使用 --accept=base。如果想要保留只包含您编辑的版本,请使用 --accept=mine-full。您也可以选择最近一次从服务器更新的版本(完全丢弃您的编辑),这可以通过 --accept=theirs-full 来实现。此外,还有其他 预设 解决类型。有关详细信息,请参阅 --accept ACTION 以及 svn 参考 - Subversion 命令行客户端

您并不局限于全有或全无的选择。如果您想要从您的更改和更新从服务器获取的更改中进行选择,可以手动修复工作文件,手动修复冲突的文本(通过检查和编辑文件中的冲突标记),然后告诉 Subversion 通过保留工作文件当前状态来解决冲突,方法是运行 svn resolve 并使用 --accept=working 选项。

svn resolve 会删除三个临时文件,并接受您指定的版本。如果命令成功完成(当然,前提是您没有选择交互式地推迟解决),Subversion 将不再认为该文件处于冲突状态。

$ svn resolve --accept working sandwich.txt
Resolved conflicted state of 'sandwich.txt'

手动解决冲突

第一次尝试手动解决冲突可能会让人感到非常可怕,但只要稍微练习一下,就会变得像骑自行车一样容易。

以下是一个示例。由于沟通失误,您和您的合作者 Sally 同时编辑了 sandwich.txt 文件。Sally 提交了她的更改,当您更新工作副本时,您遇到了冲突,需要编辑 sandwich.txt 来解决冲突。首先,让我们看一下这个文件

$ cat sandwich.txt
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Creole Mustard
Bottom piece of bread

这些小于号、等号和大于号组成的字符串是冲突标记,不是冲突的实际数据。通常,您需要确保在下次提交之前从文件中删除这些标记。前两组标记之间的文本包含您在冲突区域进行的更改

<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======

第二组和第三组冲突标记之间的文本是 Sally 提交的文本

=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2

通常,您不会仅仅删除冲突标记和 Sally 的更改,因为当三明治送达时,它不是 Sally 想要的,她会非常惊讶。这时,您需要拿起电话或走到办公室,向 Sally 解释您无法从意大利熟食店买到酸菜。 [7] 确定要提交的更改后,编辑您的文件并删除冲突标记

Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Creole Mustard
Bottom piece of bread

现在,使用 svn resolve,您就可以提交更改了

$ svn resolve --accept working sandwich.txt
Resolved conflicted state of 'sandwich.txt'
$ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."

当然,在使用 svn resolve 时,您需要谨慎,不要告诉 Subversion 您已经解决了冲突,而实际上并没有解决。一旦临时文件被删除,即使文件仍然包含冲突标记,Subversion 也会允许您提交文件。

如果您在编辑冲突文件时感到困惑,可以随时查看 Subversion 为您在工作副本中创建的三个文件,包括更新之前您的文件。您甚至可以使用第三方交互式合并工具来检查这三个文件。

丢弃更改以支持新获取的修订版

如果您遇到了冲突,并且决定要丢弃更改,可以运行 svn resolve --accept theirs-full CONFLICTED-PATH,Subversion 会丢弃您的编辑并删除临时文件

$ svn update
Updating '.':
Conflict discovered in 'sandwich.txt'.
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
        (mc) my side of conflict, (tc) their side of conflict,
        (s) show all options: p
C    sandwich.txt
Updated to revision 2.
Summary of conflicts:
  Text conflicts: 1
$ ls sandwich.*
sandwich.txt  sandwich.txt.mine  sandwich.txt.r2  sandwich.txt.r1
$ svn resolve --accept theirs-full sandwich.txt
Resolved conflicted state of 'sandwich.txt'
$

放弃:使用 svn revert

如果您决定要丢弃更改并重新开始编辑(无论是在冲突之后还是任何时候),只需恢复更改

$ svn revert sandwich.txt
Reverted 'sandwich.txt'
$ ls sandwich.*
sandwich.txt
$

请注意,当您恢复冲突文件时,不需要使用 svn resolve

提交更改

终于!您完成了编辑,合并了来自服务器的所有更改,并准备将更改提交到存储库。

svn commit 命令会将所有更改发送到存储库。当您提交更改时,需要提供一个日志消息,描述您的更改。您的日志消息将附加到您创建的新修订版。如果您的日志消息很简短,可以考虑使用命令行上的 --message (-m) 选项来提供消息

$ svn commit -m "Corrected number of cheese slices."
Sending        sandwich.txt
Transmitting file data .
Committed revision 3.

但是,如果您在工作时将日志消息保存在其他文本文件中,可以考虑通过将文件名作为 --file (-F) 选项的值传递给 Subversion,让 Subversion 从该文件中获取消息

$ svn commit -F logmsg
Sending        sandwich.txt
Transmitting file data .
Committed revision 4.

如果您没有指定 --message (-m) 或 --file (-F) 选项,Subversion 会自动启动您最喜欢的编辑器(有关 editor-cmd 的信息,请参阅 名为“常规配置”的部分),用于撰写日志消息。

[Tip] 提示

如果您正在编辑器中编写提交消息,并决定取消提交,只需退出编辑器,不保存更改即可。如果您已经保存了提交消息,只需删除所有文本,重新保存,然后中止

$ svn commit
Waiting for Emacs...Done

Log message unchanged or not specified
(a)bort, (c)ontinue, (e)dit
a
$

存储库不知道也不关心您的更改作为整体是否有意义;它只检查您没有注意时,是否有其他人更改了与您更改的相同文件。如果有人确实 进行了更改,整个提交将会失败,并显示一条消息,通知您一个或多个文件已过期

$ svn commit -m "Add another rule"
Sending        rules.txt
Transmitting file data .
svn: E155011: Commit failed (details follow):
svn: E155011: File '/home/sally/svn-work/sandwich.txt' is out of date
…

(此错误消息的具体措辞取决于您使用的网络协议和服务器,但基本原理在所有情况下都是一样的。)

此时,您需要运行 svn update,处理由此产生的所有合并或冲突,然后再次尝试提交。

这涵盖了使用 Subversion 的基本工作周期。Subversion 提供了许多其他功能,您可以使用这些功能来管理存储库和工作副本,但是您在日常使用 Subversion 时,大部分时间只涉及我们在本章中讨论过的命令。但是,我们将介绍一些您经常会使用到的其他命令。



[6] 如果您想要恢复该项目,以便它再次出现在 HEAD 中,请参阅 名为“恢复已删除的项目”的部分.

[7] 而且,如果您向他们提出要求,他们很可能会用火车把你赶出城镇。

TortoiseSVN 官方中文版 1.14.7 发布