此文本尚未完工,可能随时发生更改,并且可能无法准确描述 Apache™ Subversion® 软件的任何已发布版本。将此页面添加为书签或以其他方式推荐给其他人可能不是一个好主意。请访问 https://svnbook.subversion.org.cn/ 获取本书的稳定版本。
正如我们在 名为“Subversion 工作副本”的部分 中所述,Subversion 工作副本是一个暂存区域,用户可以在其中私下对其版本控制的数据进行更改,然后 - 当这些更改完成并准备与其他人共享时 - 将它们提交到存储库。因此,您与 Subversion 的大部分交互都将是要求您的 Subversion 客户端对本地工作副本中的一个或多个项目执行 某项操作。即使对于那些不直接操作工作副本数据本身的操作(如 svn log),使用工作副本文件或目录作为该操作的便捷目标通常也更轻松。
显然,对版本控制数据进行更改的典型方法是通过 Subversion 工作副本进行提交。幸运的是,这并不是唯一的方法。需要对版本控制数据进行相对简单更改的 Subversion 用户可以在不签出工作副本的情况下进行更改。在本节中,我们将介绍一些支持的操作。
Subversion 命令行客户端支持许多操作,这些操作可以直接针对存储库 URL 执行,以便在没有工作副本的情况下进行简单更改。其中一些在本书的其他地方有所描述,但为了方便起见,我们在此列出它们的所有内容。
可能最明显的远程提交式操作是 svn import 命令。我们在 名为“导入文件和目录”的部分 中描述了该命令,作为解释如何轻松将整个未版本控制信息的树导入您的 Subversion 存储库以开始对其进行版本控制操作的一部分。
当使用 URL 目标时,svn mkdir 和 svn delete 命令也是远程提交类型操作。这些允许用户在不使用工作副本的情况下,分别创建一个或多个新的版本控制目录,或删除(递归地)一个或多个版本控制文件或目录。每次您发出这些命令之一时,客户端都会与服务器通信,其方式类似于它将描述从工作副本添加或删除的目录的提交方式。如果没有检测到与请求的操作相关的任何问题或冲突,则服务器将在单个新修订版中提交添加或删除。
您可以使用 svn copy 或 svn move 以及两个 URL - 复制/移动源和目标 - 来直接在存储库中提交文件和目录的复制和移动。这些操作在工作副本中执行时往往是最昂贵的操作之一,但在使用存储库 URL 远程执行时,它们会在恒定时间内完成。事实上,svn copy 远程操作通常用于在 Subversion 中创建分支,正如我们将在后面的 名为“创建分支”的部分 中讨论的那样。
与常规的 svn commit 命令一样,您可以在我们迄今为止讨论的任何这些命令中提供日志消息来描述您所做的更改。使用 --file (-F)
或 --message (-m)
选项,或允许客户端提示您输入日志消息。
最后,还有一些与未版本控制修订版属性相关的操作,这些操作可以直接针对存储库执行。事实上,修订版属性在这种情况下有点独特,因为它们没有存储在工作副本中,因此必须在没有工作副本交互的情况下进行修改。请参见 名为“属性”的部分,以更详细地了解如何在 Subversion 中管理属性。
命令行客户端提供的远程提交操作支持的一个缺点是,您本质上仅限于每次提交一个操作 - 或者实际上是一种类型的操作。例如,在工作副本中使用 svn delete 后跟 svn mkdir 来替换现有的版本控制目录,这完全自然且受支持。当您提交这些操作的结果时,将在存储库中创建一个新的修订版,并且该修订版将包含您的目录的完整替换。在没有工作副本的情况下使用命令行客户端时,您实际上无法做到相同的事情,同时仍然保留更改的“在单个修订版中发生的”性质 - svn delete URL
将创建一个新的修订版以删除该目录;svn mkdir URL
将为目录的重新创建生成第二个修订版。
幸运的是,Subversion 提供了一个单独的工具,其存在仅仅是为了允许用户将一系列远程操作串联起来并将其作为原子更改提交。该工具是 svnmucc 工具 - Subversion 多 URL 命令客户端
$ svnmucc --help Subversion multiple URL command client usage: svnmucc ACTION... Perform one or more Subversion repository URL-based ACTIONs, committing the result as a (single) new revision. Actions: cp REV URL1 URL2 : copy URL1@REV to URL2 mkdir URL : create new directory URL mv URL1 URL2 : move URL1 to URL2 rm URL : delete URL put SRC-FILE URL : add or modify file URL with contents copied from SRC-FILE (use "-" to read from standard input) propset NAME VAL URL : set property NAME on URL to value VAL propsetf NAME VAL URL : set property NAME on URL to value from file VAL propdel NAME URL : delete property NAME from URL …
svnmucc 已经成为 Subversion 项目源代码树的一部分多年(作为 mucc 在大部分时间内),但直到 Subversion 1.8 它才成为 Subversion 命令行工具套件中一个完全受支持的成员。
svnmucc 工具可以对版本控制数据执行 svn 本身可以执行的任何转换。但与 svn 不同的是,svnmucc 提供的功能没有细分为子命令。相反,您在一个命令行中(或通过 --extra-args (-X)
选项从文件流中)提供一系列操作和操作数。svnmucc 支持的一些操作模仿命令行客户端的操作。您将在前面的命令输出中注意到诸如 cp
、mkdir
、mv
和 rm
这样的操作,这些操作与我们在 名为“远程命令行客户端操作”的部分 中提到的命令非常相似。但请记住,这里的关键区别在于,您可以将任意数量的这些操作一起使用在一个命令调用中,从而在存储库中产生一个已提交的修订版。
让我们以我们之前尝试简单替换远程目录的示例为例。使用 svnmucc,您可以按如下方式完成此操作
$ svnmucc rm http://svn.example.com/projects/sandbox \ mkdir http://svn.example.com/projects/sandbox \ -m "Replace my old sandbox with a fresh new one." r22 committed by harry at 2013-01-15T21:45:26.442865Z $
如您所见,svnmucc 在一个修订版中完成了 svn - 在没有工作副本的情况下 - 需要两个修订版才能完成的工作。
警告 | |
---|---|
svnmucc 与 svn 之间的另一个区别是,如果前者没有通过命令行提供提交日志消息,则目前不会提示您输入。相反,它将使用一个标准(即相对无价值的)日志消息。 |
svnmucc 工具不仅限于简单地重新混合 svn 本身可以执行的操作。它引入了命令行客户端中找不到的一些额外功能。例如,您可以使用 put 操作在存储库中添加或修改文件,从本地计算机上的文件或通过标准输入管道传输的数据中复制文件的预期新内容。该工具还提供 propset、propsetf 和 propdel 操作,这些操作可用于设置版本控制文件和目录的属性(明确地或通过从本地文件复制属性值),以及删除这些属性。目前,命令行客户端不支持这些操作。
但是,在这一点上,似乎谨慎地讨论一下使用 可以 用 svnmucc 完成的操作和 应该 完成的操作之间的区别。有两句著名的引语浮现在脑海
“凡是多给谁的,就向谁多要;凡是多托付谁的,就向谁多索取。” |
||
--耶稣 |
“能力越大,责任越大。” |
||
--“蜘蛛侠”彼得·帕克的本叔叔 |
在没有工作副本的情况下进行修改时,固有的问题是丢失了使工作副本的使用如此宝贵的冲突检测保障措施。当以典型方式使用 svn 时,更改将针对文件或目录的特定基础版本提交到服务器,这样您就不会无意中覆盖其他团队成员对同一项目的同期更改。服务器知道您在更改文件之前所用的文件版本,并且它知道自创建该修订版以来,是否其他人更改了该文件。这就是服务器拒绝您的提交所需的所有信息,当它会覆盖其他人的更改时,这会迫使您将他们的更改集成到您的工作副本中并重新考虑您自己的更改。由于这里没有工作副本,svnmucc 实际上给了您绕过这些保障措施的能力,并表现得好像存储库的当前状态恰好是您正在针对其进行操作的基础状态。但希望您会明白,这不是您应该轻易挥舞的力量。
幸运的是,svnmucc 允许您以更保守的方式使用该工具。为了提供类似于使用工作副本所提供的安全机制,svnmucc 提供了一个 --revision (-r)
选项。使用此选项,您可以手动为要提交的更改指定一个基础修订版。您选择的基线修订版最好是您能够合理地声称了解的存储库中最新的修订版。
警告 | |
---|---|
强烈建议用户使用并正确使用 |
正确使用 svnmucc put 操作最能说明应该如何使用此 --revision (-r)
选项。假设 Harry 希望更改版本控制的 README
文件的内容,而不必费心完全签出工作副本。(我们将假设使用工作副本进行此操作没有其他价值,例如,Harry 应该在他提交之前运行的脚本的存在,以验证这是一个合理的脚本。)他必须做出的第一个决定是他想使用文件的哪个修订版。通常,用户希望修改文件的最新版本。因此,Harry 查询了最后修改文件的修订版,然后使用该修订版将文件的内容提取到一个临时本地文件中
$ svn info http://svn.example.com/projects/sandbox/README Path: README URL: http://svn.example.com/projects/sandbox/README Relative URL: ^/sandbox/README Repository Root: http://svn.example.com/projects Repository UUID: 13f79535-47bb-0310-9956-ffa450edef68 Revision: 22 Node Kind: file Last Changed Author: sally Last Changed Rev: 14 Last Changed Date: 2012-09-02 10:34:09 -0400 (Sun, 02 Sep 2012) $ svn cat -r 14 http://svn.example.com/projects/sandbox/README \ > README.tmpfile $
Harry 现在有了 README
文件的副本,就像它在最后一次修改时一样。他对他希望对该文件的副本进行的编辑。当然,当他完成时,他希望将这些更改提交到存储库。
现在,如果 Harry 粗心大意地使用 svnmucc put …
在此时用他本地修改后的内容替换仓库中 README
的内容,他就滥用了 svnmucc 提供的功能。如果在提交的前几毫秒,Sally 也修改了 README
文件会怎么样?与 svn 程序一样,svnmucc 不会尝试进行任何服务器端的內容合并来保留两者的更改。相反,svnmucc 会很乐意用指定的内容替换当前最新版本的檔案。Harry 不会察觉到。Sally 会很生气。
$ svnmucc put README.tmpfile \ http://svn.example.com/projects/sandbox/README \ -m "Tweak the README file." r24 committed by harry at 2013-01-21T16:21:23.100133Z $ Message from [email protected] on pts/2 at 16:26 ... We need to talk. Now. EOF
Harry 应该回顾他最初用作更改基础的版本,将该版本提供给 svnmucc,方法是使用 --revision (-r)
选项,从而使服务器有机会在他自己的(可能是无意的)承认下,在他试图修改过时的項目时拒绝他的提交。
$ svnmucc -r 14 put README.tmpfile \ http://svn.example.com/projects/sandbox/README \ -m "Tweak the README file." svnmucc: E170004: Item '/sandbox/README' is out of date $
与其他 svnmucc 选项一样,--revision (-r)
选项在整个命令的范围内有效——该命令中指定的每个操作。这使您可以拥有与检出整个仓库的工作副本(从而拥有完全处于单一统一版本的工作副本),对该工作副本进行更改,然后一次性提交所有这些更改相同的安全措施。
如您所见,svnmucc 是 Subversion 用户工具箱中一个方便的补充。有关此工具提供的功能的完整参考,请参阅 svnmucc 参考 - Subversion 多 URL 命令客户端。