假设我有一个项目“MyFramework”,它有一些代码,用于很多解决方案。每个解决方案都有自己的源控制管理(SVN)。
MyFramework是一个内部产品,没有正式的发布时间表,解决方案也是如此。
我不想将DLL构建并复制到所有12个项目,即新开发人员应该能够只执行svn-checkout并开始工作。
在所有这些解决方案中分享MyFramework的最佳方式是什么?
答案 0 :(得分:7)
由于您提到SVN,您可以使用externals将框架项目“导入”到使用它的每个解决方案的工作副本中。这将导致这样的布局:
C:\Projects
MyFramework
MyFramework.csproj
<MyFramework files>
SolutionA
SolutionA.sln
ProjectA1
<ProjectA1 files>
MyFramework <-- this is a svn:externals definition to "import" MyFramework
MyFramework.csproj
<MyFramework files>
使用此解决方案,您可以在使用它的每个解决方案中获得MyFramework的源代码。优点是,您可以从每个解决方案中更改MyFramework的源代码(无需切换到其他项目)。
但是:同时这也是一个巨大的劣势,因为它可以让MyFramwork在为其他解决方案修改时很容易。
出于这个原因,我最近放弃了这种方法,现在将我们的框架项目视为一个完全独立的解决方案/产品(具有自己的发布时间表)。然后,所有其他解决方案都包含框架项目的特定版本的二进制文件。
这可确保对框架库所做的更改不会破坏任何重用库的解决方案。对于每个解决方案,我现在可以决定何时更新到更新版本的框架库。
答案 1 :(得分:4)
这听起来像是一场灾难......你如何应对开发人员撤销/破坏他人的工作......
如果我是你,我会将MyFrameWork置于一个完全独立的解决方案中。当开发人员想要开发12个项目中的一个时,他在一个IDE&amp;在单独的IDE中打开MyFrameWork。
如果你强名你的MyFramework Assemby&amp; GAC它,并在你的其他项目中引用它,然后“复制DLL”将不是一个问题。
您只需构建MyFrameWork(并且PostBuild事件可以运行GacUtil将其放入asssembly缓存中),然后构建您的其他项目。
答案 2 :(得分:2)
“最佳方式”取决于您的环境。我在基于TFS的持续集成环境中工作,每晚构建将二进制文件部署到共享。所有依赖项目都提到了共享。当这个变慢时,我构建了一些工具来允许开发人员拥有共享二进制文件的本地副本,而无需更改项目文件。
答案 3 :(得分:2)
12个解决方案中的任何一个解决方案是否经常需要更改“框架”代码?
如果是这样,你的框架可能是新的,只是被创建,所以我只是将框架项目包含在所有解决方案中。毕竟,如果工作要求你必须改变框架代码,那么这应该很容易。
由于从一个解决方案中进行的框架更改将影响所有其他解决方案,因此会发生中断,您将不得不处理它们。
一旦您在解决方案中工作时很少需要更改框架(这应该是您的目标),那么我将包含对框架dll的引用,并仅在需要时更新每个解决方案中的dll。
答案 4 :(得分:2)
svn:externals会很好地处理这个问题。
首先,如果对svn:externals定义使用相对URI(以^字符开头)并且尽可能将项目放在同一个存储库中,则更安全。这样,即使将subversion服务器移动到新URL,定义仍将保持有效。
其次,请确保您遵循SVN手册中的以下提示。在svn:externals定义中使用PEG-REV以避免随机破坏和不稳定标记:
你应该认真考虑使用 所有的显式修订号 你的外部定义。这样做 意味着你可以决定何时开始 拉下不同的快照 外部信息,确切地说 拉哪个快照。除了 避免获得惊喜 更改到第三方存储库 你可能没有任何控制权 结束,使用显式修订号 也意味着当你回溯你的 工作副本到以前的版本, 你的外部定义也将 恢复他们看待的方式 以前的修订......
答案 5 :(得分:1)
我同意另一张海报 - 这听起来很麻烦。但如果你不想以“正确的方式”去做,我可以想到另外两种方法。我们使用类似于下面的数字1的东西。 (对于本机C ++应用程序)
运行的脚本或批处理文件或其他进程,用于执行依赖项的获取和构建。 (仅一次)只有在回购中没有变化时才构建/执行。您需要知道要获取的标记/分支/版本。您可以将bat文件用作项目文件中的预建步骤。
将二进制文件保留在repo中(不是一个好主意)。即使在这种情况下,依赖项目也必须进行获取并且必须知道要获得的版本。
最终我们尝试为我们的项目做的是模仿我们如何使用和引用第三方库。
您可以做的是为依赖项创建一个发布包,为自己设置路径env变量。我会允许它的多个版本存在于机器上,然后依赖项目链接/引用特定版本。
像
这样的东西$(PROJ_A_ROOT) = c:\mystuff\libraryA
$(PROJ_A_VER_X) = %PROJ_A_ROOT%\VER_X
然后按特定名称或使用版本env var在依赖解决方案中引用所需的版本。
不漂亮,但确实有效。
答案 6 :(得分:1)
可扩展的解决方案是在解决方案目录上执行 svn-external,以便导入的项目与您的其他项目并行显示。原因如下:
为“导入”项目使用单独的子目录,例如externals
,通过svn-external似乎是一个好主意,直到你在项目之间有非平凡的依赖关系。例如,假设项目A依赖于项目B上的项目,项目B上项目B。然后你有一个带有项目A的解决方案S,你最终会得到以下目录结构:
# BAD SOLUTION #
S
+---S.sln
+---A
| \---A.csproj
\---externals
+---B <--- A's dependency
| \---B.csproj
\---externals
\---C <--- B's dependency
\---C.csproj
使用这种技术,您甚至可能最终在树中拥有单个项目的多个副本。这显然不是你想要的。
此外,如果您的项目使用NuGet依赖项,它们通常会在packages
顶级目录中加载。这意味着 externals
子目录中项目的NuGet引用将被破坏。
此外,如果除了SVN之外还使用Git,建议的跟踪更改的方法是为每个项目创建一个单独的Git存储库,然后为使用{{3}的解决方案创建一个单独的Git存储库对于其中的项目。如果Git子模块不是父模块的直接子目录,则 Git子模块命令将生成一个直接子目录的克隆。
将所有项目放在同一层上的另一个好处是,您可以创建一个“超级解决方案”,其中包含来自所有解决方案的项目(通过Git或svn-external跟踪),这反过来又允许您检查单个解决方案 - 重建您对单个项目所做的任何更改都与所有其他项目一致。
# GOOD SOLUTION #
S
+---S.sln
+---A
| \---A.csproj
+---B <--- A's dependency
| \---B.csproj
\---C <--- B's dependency
\---C.csproj