最佳实践:如何正确使用svn:externals

7
让我们看三种情况:
1. 这个语句很好。“999”是一个peg。这就是所谓的“旧格式”: ``` foo -r999 http://myrepo/foo ```
2. 或者,也可以像这样指定peg(在“新格式”中),并且也很好: ``` http://myrepo/foo@999 foo ```
3. 但是,在“新格式”中存在一个复杂性:`-r999`可以放在前面,这会完全改变它的含义,从而成为“操作版本”的标识。根据SVN Book,实际的peg变成了HEAD(即不再具有确定性): ``` -r999 http://myrepo/foo foo ``` 我认为这种格式可能是一个非常糟糕的想法的原因是:如果在rev 999之后将“bar”重命名为“foo”,那么实际上将检出什么内容呢?被重命名的版本bar@999。这真的有用吗?然后,稍后又发生了另一个重命名,将“baz”命名为“foo”。现在用户将检查baz@999。因此,随着时间的推移,用户将永远无法确定999是否指的是相同的代码。
#3是一个等待引起麻烦的漏洞吗?应该用鲜艳的红旗警告用户避免使用#3的格式吗?或者尽管它不确定性很高,但实际上是有用的吗?这几乎是太容易误解和出错了,因此似乎需要指定最佳实践。
SVN Book中,如果您真正深入挖掘,它会巧妙地提示用户要小心:
请注意,要小心避免天真地重新定位定义中的-rNNN部分-旧格式使用该修订版本作为peg修订版本,但新格式将其用作操作修订版本(具有peg修订版本HEAD,除非另有说明;请参见“Peg and Operative Revisions”部分,以了解这里区别的完整说明)。
2个回答

8
我同意您的观点,应该避免没有固定点的版本号。我不知道为什么不指定一个明确的固定点版本(如果您根本使用了明确的版本号),这样可以确保您始终可以回滚到该版本而不会产生歧义。在我的工作中,我们总是按照第二个格式列出我们的外部文件,其中固定点既是固定点,也是操作版本。或者,我们指向一个标签。因为标签在提交后通常不会更改(也许会调整外部文件之类的),而且在项目存储库路径的高层次上,路径不太可能更改,这应该可以实现与使用明确版本的目标一样的效果,并更有意义(对人类来说)。
请注意,您可以组合第二种和第三种格式,但这不是必需的,例如-r 123 http://example.com/svn/proj@123 proj

我接受这个答案,因为它解决/确认了使用钉子修订与操作修订的问题。然而,我也喜欢David W.提供的“不要这样做!”的答案。 - David Baird

8

使用外部文件?最佳实践?

很简单!不要这么做!

svn:externals 是那些看起来想法很好的东西,但最终导致各种问题的一种。我发现有比使用 svn:externals 更好的方法。例如,您可以使用 Maven 或 Ivy 来管理依赖关系。

然而,如果我必须使用 svn:externals,我将使用标签而不是绝对修订版本。这在新版本的 Subversion 中效果更佳,我通常不必担心使用特定修订版本,但是随着文件被重命名和移动,文件的 URL 也会改变。对我来说,标签是不可变的,一旦创建,它们永远不会改变。

这也鼓励您将您的 svn:externals 视为完全独立的项目。例如,您可以谈论 Foundation 的 4.3 版本。您的 svn:externals 命令将类似于:

$ svn propset svn:externals `^/tags/4.3/foundation foundation` .

注意我没有在标签中添加URL协议或服务器名称。如果外部资源与项目在同一代码库中,我几乎总是使用相对路径。想象一下,如果您以前使用的是 http:// ,现在改用 https:// 或者您的Subversion存储库机器的名称发生了变化,这种方案仍然可以正常工作,但是如果我这样做了,它就会出现故障:

$ svn propset svn:externals "http://server.com/svn//tags/foundation foundation" .

我是一个可悲的骗子

我目前正在从事一个项目,但并没有按照上面所提到的做法。我没有使用标签来管理svn:externals,而我们所有的项目都必须使用它们。

在这家公司中,他们在jar依赖管理方面存在严重问题。他们生产了约十几个基础jar包,用于多个项目。每个项目都有不同的指定这些jar包的方式。

为了解决这个问题,我建立了一个特殊的Ivy项目,称为ivy.dir。开发人员被告知通过以下命令将此项目合并到其当前项目中:

$ svn propset svn:externals "../ivy.dir ivy.dir" .

ivy.dir 内部,有完整的设置来将您的项目集成到 Ivy 中。Ivy 预配置为使用我们的新公司 Maven 仓库。这里有我们各种构建工具。
这种方法使得将 Ivy 和良好的依赖管理融入我们的项目非常容易。您只需将 ivy.dir/ivy.tasks.xml 文件导入到当前的 build.xml 中,并使用 <ivy:cachepath> 来创建您的类路径。一个好的、格式正确的 build.xml 只需要进行轻微修改就可以运行。
我甚至创建了一个特殊的 <jar.macro> 宏定义。它几乎与 <jar> 宏兼容,但它会自动从 ivy.xml 创建一个 pom.xml 文件,并将其嵌入到构建的 Jar 中(还将包括 Jenkins 项目名称、构建日期和构建编号)。
通过使用相对 URL,我使得分支或标记所有内容变得容易(并且 ivy.dir 项目也被标记了)。
这是一种奇怪的使用 svn:externals 的方式,但它使我们摆脱了以前许多项目使用 svn:externals 来拉取存储在仓库中的 jar 的可怕用法。

我非常赞同使用标签的想法!我会将其添加到我的答案中。但有时,当你正在积极开发一个库或其他东西时,可能还没有标签可以指向。在这种情况下,应该使用明确的修订版本。 - Ben
1
问题在于不断变化的修订版本使得保持更新非常非常困难。你分支项目,突然你的 svn:externals URL 改变了。正如我在第二个答案中所说,我使用 svn:externals 与 Ivy 集成。我们有一个特殊的属性文件 (ivy.version.properties),其中包含实际的 jar 版本 ID。它在基础 jar 开发进行时设置为 SNAPSHOT,并在我们为发布完成基础 jar 时切换到 _release_。 - David W.
我发现Ivy/Maven集成在这种类型的库发布方面比尝试使用svn:externals更有效。当然,这仅适用于Java而不是C,但您可以采用类似的概念。 C库存储在单独的服务器上,并且Makefiles使用wgetcurl来下载正确版本。 - David W.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接