在SVN存储库中有一个大项目。我想在其他应用程序中使用项目的一些模块,所以我考虑从我的主SVN存储库中签出它们,以便我可以保持我的代码更新。
我如何"导出"我的存储库的一个文件夹/模块,以便我可以只签出该模块到其他项目?我想要包含该模块的其他项目也在它们自己的SVN存储库中。
在简历中,我希望能够做SVN更新到主仓库,但做提交到项目仓库。
我希望你能明白我想做什么。
对DavidW的回答:
- 我有一个存储库与多个项目,但我可能会改变这一点如果有必要的话)。
- 我想分享源代码。这是一个PHP项目。我我正在分叉模块。(我有一个全局通用项目,如果我的
客户需要一些特定的功能, - 我想为该客户端创建一个单独的项目(在svn中也单独)。但是我想
有一种方法可以将主项目中的一些更改合并到
客户端项目。(例如:全局错误修复或功能)。
几个问题:
- 您是在谈论多个存储库,还是在相同的存储库中的多个项目?
- 如果你借用了其他模块的代码,你是在保持它与其他模块的同步,还是你在分叉那个模块?
- 你真正想要分享的是什么?您是否必须共享源代码或编译后的输出(Unix C/C+中的
*.so
或*.a
, Java中的*.jar
等)?
你给出的答案在很大程度上取决于你对这些问题的回答。
让我们假设代码实际上是共享的。你在其中一个做的就是你想在另一个做的。如果您在中更改了项目,则其他项目中的代码也会更改。
使用svn:externals
。这是您放置在目录上的属性。它所做的是将Subversion URL关联到子目录名称。例如:
$ svn propset svn:externals "http://svn.vegibanc.com/svn/trunk/project/stuff utils" .
将属性放置在当前目录上。当您执行更新或签出时,将在项目中创建一个名为utils
的目录,Subversion将自动将http://svn.vegibanc.com/svn/trunk/project/stuff
签入该目录。这是魔法,但就像所有的魔法一样,它也有光明和黑暗的一面。
首先是光明的一面:
这是在两个项目之间共享代码。您在utils
目录中进行更改并提交更改,project
中的stuff
子目录将被更新。我用它在我的项目中构建工具。如果我升级了工具,所有的项目都会得到升级后的工具。
现在,黑暗的一面:
如果你像我给你看的那样定义svn:externals
,你会后悔的。想象一下,如果您决定为一个发布版本分支您的工作。那么,您的utils
目录仍然指向project/stuff
的trunk
。如果你的分支版本是2.1,而主干现在正在2.2上工作,你会在utils
中得到一些你不想要的东西。
更糟糕的是,如果你创建了一个标签,这个标签会继续改变,因为主干中的utils
目录仍然在改变。
$ svn propset svn:externals "-r23283 ^/trunk/project/stuff@23283 utils" .
$ svn propset svn:externals "^/tags/2.3.3/project/stuff utils" .
在第一个示例中,我指的是URL的特定的修订。它是完全不变的。如果我需要把它指向另一个版本,我需要改变svn:externals
属性本身。
第二个指向一个特定的标记。它不是安全的,因为标签可以更改,但是我可以通过这种方式将我的外部依赖视为一个发布。我使用的是2.3.3版的stuff工具。
两者都使用^
快捷方式,它简单地表示 Subversion Repository根。这样,如果您将Subversion存储库移动到另一个系统,或者从http
更改到svn
,您的外部仍然可以工作。当然,如果您这样做,您将永远无法更改svn:externals
下的代码。这不是你想要的。
你也可以使用相对 url,但是它们更危险。
想象一下你的两个项目是这样的,你想让stuff目录和svn:external
链接到utils目录:
http://svn.vegibanc.com/svn/trunk/project/foo/stuff
http://svn.vegibanc.com/svn/trunk/project/bar/utils
项目一起分支,一起标记。你可以这样做:
$ co http://svn.vegibanc.com/svn/trunk/project/bar bar-trunk
$ cd project-bar
$ svn propset svn:externals "../foo/stuff utils" .
这会将stuff目录外部链接到utils目录。然而,它是以一种相对的方式完成的。如果你这样做:
$ cp http://svn.vegibanc.com/svn/trunk http://svn.vegibank.com/svn/branches/2.3
你的utils目录仍然会外部链接到foo项目下的stuff目录,但它们都将在2.3分支上。
更改bar/utils
中的代码将更改foo/stuff
中的代码,反之亦然。你仍然在共享代码,但在某种程度上,两个项目仍然在同一个分支中。
之后,如果你这样标记:
$ cp http://svn.vegibank.com/svn/branches/2.3 http://svn.vegibank.com/svn/tags/2.3.0
你的标签2.3.0不太可能改变,因为外部链接和它们链接到的东西都被那个标签包围了。
上面的假设是你们正在共享代码,并且任何一个项目中的更改都应该影响另一个项目。
更好的方法是让foo
创建一个可以存储在发布服务器上的编译对象(如JAR文件或*.so)。您将此编译后的对象视为具有自己版本控制的自己的项目,并且您的项目将依赖于此对象的特定版本。不幸的是,这并不总是有效的。
如果您只是对代码进行分叉,那么从存储库中的一个位置到另一个位置执行svn cp
操作。您可以在不影响其他项目的情况下进行更改,反之亦然。更好的是,您可以在两个位置之间来回合并更改,以保持它们的同步。
希望这能回答你的问题。如果你能扩展你的问题,给我们更多你想要的细节,我将能够更新我的答案。
- 如果你想在Subversion存储库中使用共享代码-它是svn:externals
- 如果你想从共享代码的主线移植到客户特定版本的共享代码-在svn术语中是"供应商分支"
结合a)和b)会得到你需要的结果
- 选择一些节点(客户存储库的主干之外),您将链接到dev-repo中的共享节点
- 创建外部定义(如果你需要在提交到dev-repo后手动更新定义的成本,最好使用PEG-revision)
- 复制节点到位置,其中in必须在活动项目中(
svn cp ...
) - 代码…
- 当你在dev-repo中有更改时,你想要将其转移到客户repo - update外部以需要的修订,将"Vendor"节点合并到"Live"
如果你有客户的回购
- /vendor/lib(其中lib是来自外部repo的目录)*/trunk/common/lib(以上库的客户版本)
将lib-mainline的更改从/vendor/lib合并到/trunk/common/lib(在Working Copy的相应节点中为您的trunk)
David关于外部环境的注释仍然有效、正确和有用