本文档旨在描述 Subversion 1.6.x 系列。如果您运行的是其他版本的 Subversion,我们强烈建议您访问 https://svnbook.subversion.org.cn/ 并查阅适合您 Subversion 版本的文档。

基本工作周期

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
U    foo.c
U    bar.c
Updated to revision 2.
$

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

当服务器通过 svn update 将更改发送到您的工作副本时,每个项目旁边都会显示一个字母代码,以告知您 Subversion 执行了哪些操作来使您的工作副本更新。要了解这些字母的含义,请运行 svn help update 或查看 svn update (up)

进行您的更改

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

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

svn add FOO

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

svn delete FOO

使用此命令来计划从存储库中删除文件、目录或符号链接 FOO。如果 FOO 是一个文件或链接,它将立即从您的工作副本中删除。如果 FOO 是一个目录,它不会被删除,但 Subversion 会计划将其删除。当您提交更改时,FOO 将完全从您的工作副本和存储库中删除。[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 中,更新和状态报告功能是完全独立的。有关更多详细信息,请参阅 名为“区分状态和更新”的部分

如果您在工作副本的顶层运行 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)

检查本地修改的详细信息

检查更改的另一种方法是使用 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 命令通过将您的工作文件与原始文本基准进行比较来生成此输出。计划添加的文件将显示为所有行都已添加的文件;计划删除的文件将显示为所有行都已从这些文件中删除的文件。svn diff 的输出与 patch 程序兼容。patch 程序读取并应用 补丁文件(或 补丁),这些文件描述了对一个或多个文件所做的更改。因此,您可以通过从 svn diff 的重定向输出中创建补丁文件,与其他人共享您在工作副本中所做的更改,而无需先提交这些更改。

$ svn diff > patchfile
$

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

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

修正您的错误

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

幸运的是,在 Subversion 中,撤消工作并从头开始并不需要如此复杂的操作。只需使用 svn revert 命令即可

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

在此示例中,Subversion 通过使用文本基准区域中缓存的原始版本覆盖该文件,将其恢复到修改前的状态。但请注意,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
U    INSTALL
G    README
Conflict discovered in 'bar.c'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-conflict,
        (s) show all options: 

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

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

…
Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-conflict,
        (s) show all options: s

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

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

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

  (p)  postpone         - mark the conflict to be resolved later
  (l)  launch           - launch external tool to resolve conflict
  (s)  show all         - show this list

Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-conflict,
        (s) show all options:

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

(e) edit

在环境变量 EDITOR 中设置的您喜欢的编辑器中打开冲突文件。

(df) diff-full

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

(r) resolved

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

(dc) display-conflict

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

(mc) mine-conflict

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

(tc) theirs-conflict

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

(mf) mine-full

丢弃从服务器接收到的对所审阅文件的全部新更改,但保留对该文件的所有本地更改。

(tf) theirs-full

丢弃对所审阅文件的所有本地更改,仅使用从服务器接收到的该文件的全部新更改。

(p) postpone

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

(l) launch

启动外部程序来执行冲突解决。这需要预先进行一些准备工作。

(s) show all

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

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

交互查看冲突差异

在决定如何交互式地处理冲突之前,您可能希望先查看确切的冲突内容。在交互式冲突解决提示中,可以使用两个命令来帮助您完成此操作。第一个是 diff-full 命令 (df),它将显示对目标文件的全部本地修改,以及任何冲突区域。

…
Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-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) 命令仅显示冲突区域,而不是文件的所有更改。此外,该命令使用略微不同的冲突区域显示格式,使您能够更轻松地比较这三个状态下文件在这些区域中的内容:原始未编辑状态;应用本地更改并忽略服务器的冲突更改状态;仅应用服务器的传入更改并恢复本地冲突更改状态。

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

交互式解决冲突差异

有几种不同的方法可以交互式地解决冲突,其中两种方法允许您选择性地合并和编辑更改,其余方法允许您简单地选择文件的某个版本并继续操作。

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

无论您本地的 Unix 狂热分子可能告诉您什么,在您喜欢的文本编辑器中手动编辑文件是一种比较低技术含量的冲突修复方法(请参阅“手动合并冲突”部分了解详细步骤)。为此,Subversion 提供了 launch 解决命令 (l),用于启动一个花哨的图形合并工具(请参阅“外部合并”部分)。

如果您决定不需要合并任何更改,而只是想接受文件的某个版本,您可以使用 mine-full 命令 (mf) 选择您的更改(也称为 mine),或者使用 theirs-full 命令 (tf) 选择他们的更改。

最后,还提供了一对折衷方案。 mine-conflict (mc) 和 theirs-conflict (tc) 命令分别指示 Subversion 将您的本地更改或服务器的传入更改选为文件中所有冲突的“获胜者”。但与 mine-fulltheirs-full 命令不同,这些命令会在文件中未检测到冲突的区域保留您的本地更改和从服务器接收到的更改。

推迟冲突解决

这听起来像是避免婚姻纠纷的合适部分,但实际上仍然与 Subversion 有关,所以请继续阅读。如果您在执行更新时遇到未准备查看或解决的冲突,您可以在运行 svn update 时键入 p,以文件为单位推迟解决冲突。如果您事先知道不想交互式地解决任何冲突,则可以将 --non-interactive 选项传递给 svn update,任何冲突文件将自动标记为 C

C(代表 Conflicted)表示服务器的更改与您的更改重叠,现在您必须在更新完成后手动选择它们。

  • 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
Conflict discovered in 'sandwich.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-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: Commit failed (details follow):
svn: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict

如果您推迟了冲突,则需要在 Subversion 允许您提交更改之前解决冲突。您将使用 svn resolve 命令和 --accept 选项的几个参数之一来完成此操作。

如果您想选择最后检出并进行编辑之前文件的版本,请选择 base 参数。

如果您想选择仅包含您的编辑的版本,请选择 mine-full 参数。

如果您想选择最新的更新从服务器提取的版本(从而完全丢弃您的编辑),请选择 theirs-full 参数。

但是,如果您想从您的更改和更新从服务器提取的更改中进行选择,手动合并冲突文本(通过检查和编辑文件中的冲突标记),然后选择 working 参数。

svn resolve 将删除三个临时文件并接受您使用 --accept 选项指定的版本,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 与本章中处理的大多数其他命令不同,它要求您明确列出要解决的任何文件名。无论如何,您都要谨慎,仅在确定已修复文件中的冲突后使用 svn resolve,因为一旦删除了临时文件,Subversion 即使文件仍然包含冲突标记,也会允许您提交文件。

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

丢弃您的更改,转而使用新提取的版本

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

$ svn update
Conflict discovered in 'sandwich.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (mc) mine-conflict, (tc) theirs-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.

但是,如果你在工作时一直在其他文本文件中编写日志消息,你可能希望告诉 Subversion 从该文件中获取消息,方法是将该文件的名称作为 --file (-F) 选项的值传递。

$ 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
svn: Commit failed (details follow):
svn: File '/sandwich.txt' is out of date
…

(此错误消息的具体措辞取决于你使用的网络协议和服务器,但其含义在所有情况下都是相同的。)

此时,你需要运行 svn update,处理任何由此产生的合并或冲突,并再次尝试提交。

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



[6] 当然,永远不会从仓库中完全删除任何内容——只是从其 HEAD 修订版中删除。你可以继续访问先前修订版中已删除的项目。如果你希望恢复该项目,使其再次出现在 HEAD 中,请参见 名为“恢复已删除的项目”的部分

[7] 如果你向他们要求,他们很可能会把你赶出城外。