11

假设我有一个包含一些代码的项目“MyFramework”,这些代码用于很多解决方案。每个解决方案都有自己的源代码控制管理 (SVN)。

MyFramework 是一个内部产品,没有正式的发布时间表,解决方案也是如此。

我宁愿不必为所有 12 个项目构建和复制 DLL,即新开发人员应该能够只执行svn-checkout并开始工作。

在所有这些解决方案中共享 MyFramework 的最佳方式是什么?

4

7 回答 7

7

由于您提到 SVN,您可以使用外部将框架项目“导入”到使用它的每个解决方案的工作副本中。这将导致这样的布局:

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 的某些解决方案时破坏另一个解决方案。

出于这个原因,我最近放弃了这种方法,现在将我们的框架项目视为一个完全独立的解决方案/产品(具有自己的发布时间表)。然后,所有其他解决方案都包含特定版本的框架项目二进制文件。

这可确保对框架库所做的更改不会破坏任何重用库的解决方案。对于每个解决方案,我现在可以决定何时更新到更新版本的框架库。

于 2009-05-29T13:10:58.993 回答
4

这听起来像是一场灾难……您如何应对开发人员撤消/破坏他人的工作……

如果我是你,我会把 MyFrameWork 放在一个完全独立的解决方案中。当开发人员想要开发 12 个项目中的一个时,他会在一个 IDE 中打开该项目解决方案并在单独的 IDE 中打开 MyFrameWork。

如果您将 MyFramework Assemby & GAC 命名为强名称,并在您的其他项目中引用它,那么“复制 DLL”将不是问题。

您只需构建 MyFrameWork(并且 PostBuild 事件可以运行 GacUtil 将其放入程序集缓存中),然后构建您的其他项目。

于 2009-05-29T13:05:33.653 回答
2

“最佳方式”将取决于您的环境。我在基于 TFS 的持续集成环境中工作,每晚构建将二进制文件部署到共享中。所有依赖项目都引用了共享。当这变得缓慢时,我构建了一些工具来允许开发人员拥有共享二进制文件的本地副本,而无需更改项目文件。

于 2009-05-29T13:13:06.600 回答
2

12 种解决方案中的任何一种都需要定期更改“框架”代码吗?

如果是这样,您的框架可能是新的并且刚刚创建,所以我只是将框架项目包含在所有解决方案中。毕竟,如果工作要求您必须更改框架代码,那么这样做应该很容易。

由于从一种解决方案对框架所做的更改会影响所有其他解决方案,因此会发生中断,您将不得不处理它们。

一旦您在解决方案中工作时很少需要更改框架(这应该是您的目标),那么我将包含对框架 dll 的引用,并仅根据需要更新每个解决方案中的 dll。

于 2009-05-29T13:23:48.233 回答
2

如果你遵循一些规则,svn:externals会很好地处理这个问题。

首先,如果您对 svn:externals 定义使用相对 URI(以 ^ 字符开头)并尽可能将项目放在同一个存储库中,这样会更安全。这样,即使颠覆服务器移动到新的 URL,定义也将保持有效。

其次,确保您遵循 SVN 书中的以下提示。在你的 svn:externals 定义中使用 PEG-REVs 来避免随机损坏和不稳定的标签:

您应该认真考虑在所有外部定义中使用明确的修订号。这样做意味着您可以决定何时拉取外部信息的不同快照,以及拉取哪个快照。除了避免对您可能无法控制的第三方存储库进行更改之外,使用明确的修订号还意味着当您将工作副本回溯到以前的修订时,您的外部定义也将恢复到它们的外观在之前的修订中...

于 2009-05-29T17:07:20.583 回答
1

我同意另一张海报——这听起来很麻烦。但是,如果您不想以“正确的方式”来做,我可以想到另外两种方法。我们使用了类似于下面的数字 1 的东西。(对于本机 C++ 应用程序)

  1. 执行获取和构建依赖项的脚本或批处理文件或其他运行的进程。(仅一次)仅当存储库中没有更改时才构建/执行。您将需要知道要获取的标签/分支/版本。您可以在项目文件中使用 bat 文件作为预构建步骤。

  2. 将二进制文件保存在 repo 中(不是一个好主意)。即使在这种情况下,依赖项目也必须进行获取,并且必须知道要获取什么版本。

最终,我们试图为我们的项目做的是模仿我们如何使用和引用 3rd 方库。

您可以做的是为依赖项创建一个发布包,为自己设置一个路径环境变量。我会允许它的多个版本存在于机器上,然后依赖项目链接/引用特定版本。

就像是

$(PROJ_A_ROOT) = c:\mystuff\libraryA

$(PROJ_A_VER_X) = %PROJ_A_ROOT%\VER_X

然后通过特定名称或使用版本 env var 在依赖解决方案中引用您想要的版本。

不漂亮,但它有效。

于 2009-05-29T13:08:56.033 回答
1

一个可扩展的解决方案是在解决方案目录上执行svn-external ,以便您导入的项目与您的其他项目平行。其原因如下。

为“导入的”项目使用单独的子目录,例如externals,通过 svn-external 似乎是个好主意,除非您在项目之间有非平凡的依赖关系。例如,假设项目 A 依赖于项目 B 上的项目,项目 B 依赖于项目 C。如果您有一个解决方案 S 和项目 A,您将最终得到以下目录结构:

# BAD SOLUTION #
S
+---S.sln
+---A
|   \---A.csproj
\---externals
    +---B     <--- A's dependency
    |   \---B.csproj
    \---externals
        \---C     <--- B's dependency
            \---C.csproj

使用这种技术,您甚至可能最终在树中拥有单个项目的多个副本。这显然不是你想要的。

此外,如果您的项目使用NuGet依赖项,它们通常会在packages顶级目录中加载。这意味着子目录中项目的 NuGet 引用externals将被破坏。

此外,如果您在 SVN 之外使用Git ,则建议的跟踪更改的方法是为每个项目拥有一个单独的 Git 存储库,然后为git submodule用于其中项目的解决方案创建一个单独的 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
于 2013-10-03T09:10:08.483 回答