我们用 C# 开发 .NET 企业软件。我们正在寻求改进我们的版本控制系统。我以前使用过 mercurial,并且一直在我们公司尝试使用它。但是,由于我们开发企业产品,因此我们非常关注可重用的组件或模块。我一直在尝试使用 mercurial 的子存储库来管理组件和依赖项,但遇到了一些困难。以下是源代码控制/依赖管理的基本要求:
- 可重复使用的组件
- 由源共享(用于调试)
- 依赖于 3rd 方二进制文件和其他可重用组件
- 可以在消费产品的背景下开发并致力于源代码控制
- 依赖项
- 产品依赖于 3rd 方二进制文件和其他可重用组件
- 依赖有自己的依赖
- 应通知开发人员依赖项中的版本冲突
这是我一直在使用的 mercurial 结构:
一个可重用的组件:
SHARED1_SLN-+-docs
|
+-libs----NLOG
|
+-misc----KEY
|
+-src-----SHARED1-+-proj1
| +-proj2
|
+-tools---NANT
第二个可重用组件,使用第一个:
SHARED2_SLN-+-docs
|
+-libs--+-SHARED1-+-proj1
| | +-proj2
| |
| +-NLOG
|
+-misc----KEY
|
+-src-----SHARED2-+-proj3
| +-proj4
|
+-tools---NANT
消耗这两种成分的产品:
PROD_SLN----+-docs
|
+-libs--+-SHARED1-+-proj1
| | +-proj2
| |
| +-SHARED2-+-proj3
| | +-proj4
| |
| +-NLOG
|
+-misc----KEY
|
+-src-----prod----+-proj5
| +-proj6
|
+-tools---NANT
笔记
- 回购是大写
- 所有子回购都被假定为子回购
- 第 3 方(二进制)库和内部(源)组件都是位于 libs 文件夹中的子存储库
- 第 3 方库保存在单独的 mercurial 存储库中,以便使用项目可以引用特定版本的库(即旧项目可能引用 NLog v1.0,新项目可能引用 NLog v2.0)。
- 所有 Visual Studio .csproj 文件都位于第 4 级(proj* 文件夹),允许相对引用依赖项(即所有引用 NLog 的 Visual Studio 项目的 ../../../libs/NLog/NLog.dll)
- 所有 Visual Studio .sln 文件都位于第二级(src 文件夹),因此在将组件“共享”到使用组件或产品时不会包含它们
- 开发人员可以自由组织他们认为合适的源文件,只要源是使用 Visual Studio 项目的 proj* 文件夹的子级(即 proj* 文件夹可以有 n 个子级,包含各种源/资源)
- 如果 Bob 正在开发 SHARED2 组件和 PROD1 产品,那么他在 PROD1_SLN 存储库中更改 SHARED2 源(比如属于 proj3 的源)并提交这些更改是完全合法的。我们不介意有人在消费项目的上下文中开发图书馆。
- 内部开发的组件(SHARED1 和 SHARED2)通常由源包含在使用项目中(在 Visual Studio 中添加对项目的引用而不是浏览到 dll 引用)。这允许增强调试(单步执行库代码),允许 Visual Studio 管理何时需要重建项目(修改依赖项时),并允许在需要时修改库(如上述注释中所述)。
问题
如果 Bob 在 PROD1 上工作,而 Alice 在 SHARED1 上工作,那么 Bob 怎么知道 Alice 何时将更改提交到 SHARED1。目前使用 Mercurial,Bob 被迫在每个子存储库中手动拉取和更新。如果他从 PROD_SLN 存储库推/拉到服务器,他永远不知道子存储库的更新。Mercurial wiki对此进行了描述。当 Bob 从服务器中提取最新的 PROD_SLN 时,如何通知他子存储库的更新?理想情况下,应该通知他(最好在拉取期间),然后必须手动决定他要更新哪些子存储库。
假设 SHARED1 引用 NLog v1.0(mercurial 中的 commit/rev abc),SHARED2 引用 Nlog v2.0(mercurial 中的 commit/rev xyz)。如果 Bob 在 PROD1 中吸收了这两个组件,则应该让他意识到这种差异。虽然从技术上讲,Visual Studio/.NET 将允许 2 个程序集引用不同版本的依赖项,但我的结构不允许这样做,因为 NLog 的路径对于依赖于 NLog 的所有 .NET 项目都是固定的。Bob 怎么知道他的两个依赖有版本冲突?
如果 Bob 正在为 PROD1 设置存储库结构并希望包含 SHARED2,那么他如何知道 SHARED2 需要哪些依赖项?使用我的结构,他必须手动克隆(或在服务器上浏览)SHARED2_SLN 存储库,然后查看 libs 文件夹,或者查看 .hgsub 文件以确定他需要包含哪些依赖项。理想情况下,这将是自动化的。如果我在我的产品中包含 SHARED2,则 SHARED1 和 NLog 也会自动包含在内,如果与其他依赖项存在版本冲突,则会通知我(参见上面的问题 2)。
更大的问题
mercurial 是正确的解决方案吗?
有更好的水银结构吗?
这是对 subrepos 的有效使用(即 Mercurial 开发人员将subrepos标记为最后手段的功能)?
使用 mercurial 进行依赖管理有意义吗?我们可以使用另一个工具进行依赖管理(可能是内部 NuGet 提要?)。虽然这对 3rd 方依赖项很有效,但它确实会给内部开发的组件带来麻烦(即,如果它们是积极开发的,开发人员将不得不不断更新提要,我们必须在内部为它们提供服务,而且它不允许由消费项目修改的组件(注 8 和问题 2)。
您有更好的企业 .NET 软件项目解决方案吗?
参考
I have read several SO questions and found this one to be helpful, but the accepted answer suggests using a dedicated tool for dependencies. While I like the features of such a tool it does not allowed for dependencies to be modified and committed from a consuming project (see Bigger Question 4).