本文档旨在描述 Subversion 1.4。如果您正在运行较新版本的 Subversion,我们强烈建议您访问 https://svnbook.subversion.org.cn/ 并查阅适合您的 Subversion 版本的书籍。
另一个常见的版本控制概念是 标签。标签只是一个项目在时间上的“快照”。在 Subversion 中,这个概念似乎已经无处不在。每个仓库版本恰恰就是这样——每次提交后文件系统的快照。
然而,人们经常希望给标签起更人性化的名称,比如 release-1.0
。他们还希望对文件系统的较小子目录进行快照。毕竟,记住软件的 release-1.0 版本是第 4822 个版本的某个特定子目录并不容易。
再次,svn copy 命令可以解决这个问题。如果您想创建 /calc/trunk
的快照,使其与 HEAD
版本中的一模一样,那么请复制它
$ svn copy http://svn.example.com/repos/calc/trunk \ http://svn.example.com/repos/calc/tags/release-1.0 \ -m "Tagging the 1.0 release of the 'calc' project." Committed revision 351.
此示例假设 /calc/tags
目录已存在。(如果不存在,您可以使用 svn mkdir 创建它。)复制完成后,新的 release-1.0
目录将永远是项目在您进行复制时 HEAD
版本中的快照。当然,您可能希望更准确地指定要复制的版本,以防其他人可能在您不注意的时候提交了对项目的更改。因此,如果您知道 /calc/trunk
的第 350 个版本正是您想要的快照,那么您可以通过向 svn copy 命令传递 -r 350
来指定它。
等等,这个创建标签的过程和我们创建分支的过程不是一样的吗?是的,事实上,确实如此。在 Subversion 中,标签和分支之间没有区别。它们都是通过复制创建的普通目录。就像分支一样,复制的目录成为“标签”的唯一原因是 人类 决定以这种方式对待它:只要没有人提交到该目录,它就永远保持为快照。如果人们开始向它提交,它就会变成一个分支。
如果您是仓库管理员,您可以采用两种方法来管理标签。第一种方法是“不干涉”:作为项目策略的一部分,决定您的标签将存储在哪里,并确保所有用户都知道如何处理他们在那里复制的目录。(也就是说,确保他们知道不要向这些目录提交。)第二种方法更加谨慎:您可以使用 Subversion 提供的访问控制脚本之一来防止任何人进行除在标签区域创建新副本之外的任何操作(参见 第 6 章,服务器配置。)但是,谨慎的方法通常没有必要。如果用户不小心将更改提交到标签目录,您可以简单地撤消更改,如上一节所述。毕竟,这就是版本控制的意义。
有时您可能希望您的“快照”比单个目录在单个版本中的快照更复杂。
例如,假设您的项目比我们的 calc
示例大得多:假设它包含许多子目录和更多文件。在您的工作过程中,您可能会决定需要创建一个工作副本,该副本旨在包含特定功能和错误修复。您可以通过选择性地将文件或目录回滚到特定版本(使用 svn update -r 命令)或将文件和目录切换到特定分支(使用 svn switch 命令)来实现这一点。完成后,您的工作副本将成为来自不同版本的不同仓库位置的混合体。但是在测试后,您知道这是您需要的精确数据组合。
现在是时候创建快照了。将一个 URL 复制到另一个 URL 在这里不起作用。在这种情况下,您希望对您当前的工作副本排列进行快照并将其存储在仓库中。幸运的是,svn copy 实际上有四种不同的用途(您可以在 第 9 章,Subversion 完整参考 中阅读有关这些用途的信息),包括将工作副本树复制到仓库中
$ ls my-working-copy/ $ svn copy my-working-copy http://svn.example.com/repos/calc/tags/mytag Committed revision 352.
现在,仓库中有一个新的目录,/calc/tags/mytag
,它是您工作副本的精确快照——混合版本、URL 和所有内容。
其他用户已经找到了此功能的有趣用途。有时会遇到这种情况,您对工作副本进行了一些本地更改,并且希望与您的合作者共享这些更改。与其运行 svn diff 并发送补丁文件(它不会捕获树更改、符号链接更改或属性更改),不如使用 svn copy 将您的工作副本“上传”到仓库的私有区域。然后,您的合作者可以检出您的工作副本的逐字副本,或者使用 svn merge 接收您的精确更改。
虽然这是一种上传工作副本的快速快照的好方法,但请注意,这 不是 创建分支的理想方法。分支创建应该是一个独立的事件,这种方法将分支创建与对文件的额外更改混为一谈,所有这些都包含在一个版本中。这使得(以后)很难识别单个版本号作为分支点。
您是否曾经发现自己正在进行一些复杂的编辑(在您的 /trunk
工作副本中),然后突然意识到,“嘿,这些更改应该放在它们自己的分支中?”” 执行此操作的一个很好的技术可以概括为两步
$ svn copy http://svn.example.com/repos/calc/trunk \ http://svn.example.com/repos/calc/branches/newbranch Committed revision 353. $ svn switch http://svn.example.com/repos/calc/branches/newbranch At revision 353.
与 svn update 相似,svn switch 命令会保留您的本地编辑。此时,您的工作副本现在反映了新创建的分支,您的下一个 svn commit 命令将把您的更改发送到那里。