如何使用mercurial子目录来共享组件和依赖项?

cod*_*yzu 11 mercurial shared-libraries dependency-management mercurial-subrepos

我们用C#开发.NET Enterprise软件.我们正在寻求改进我们的版本控制系统.我之前使用过mercurial并且一直在我们公司进行实验.但是,由于我们开发企业产品,因此我们非常关注可重用的组件或模块.我一直在尝试使用mercurial的子repos来管理组件和依赖,但是遇到了一些困难.以下是源代码管理/依赖关系管理的基本要求:

  1. 可重复使用的组件
    1. 按源共享(用于调试)
    2. 依赖于第三方二进制文件和其他可重用组件
    3. 可以在消费产品的背景下开发并承诺源控制
  2. 依赖
    1. 产品依赖于第三方二进制文件和其他可重用组件
    2. 依赖关系有自己的依赖关系
    3. 应通知开发人员依赖项中的版本冲突

这是我一直在使用的mercurial结构:

可重用的组件:

SHARED1_SLN-+-docs
            |
            +-libs----NLOG
            |
            +-misc----KEY
            |
            +-src-----SHARED1-+-proj1
            |                 +-proj2
            |
            +-tools---NANT
Run Code Online (Sandbox Code Playgroud)

第二个可重用的组件,消耗第一个:

SHARED2_SLN-+-docs
            |
            +-libs--+-SHARED1-+-proj1
            |       |         +-proj2
            |       |
            |       +-NLOG
            |
            +-misc----KEY
            |
            +-src-----SHARED2-+-proj3
            |                 +-proj4
            |
            +-tools---NANT            
Run Code Online (Sandbox Code Playgroud)

消耗两种组分的产品:

PROD_SLN----+-docs
            |
            +-libs--+-SHARED1-+-proj1
            |       |         +-proj2
            |       |
            |       +-SHARED2-+-proj3
            |       |         +-proj4
            |       |
            |       +-NLOG
            |
            +-misc----KEY
            |
            +-src-----prod----+-proj5
            |                 +-proj6
            |
            +-tools---NANT
Run Code Online (Sandbox Code Playgroud)

笔记

  1. Repos在CAPS中
  2. 假设所有儿童回购都是子项目
  3. 第三方(二进制)库和内部(源)组件都是位于libs文件夹中的子库
  4. 第三方库保存在单独的mercurial repos中,以便消费项目可以引用特定版本的库(即旧项目可以引用NLog v1.0,而较新的项目可以引用NLog v2.0).
  5. 所有Visual Studio .csproj文件都在第4级(proj*文件夹),允许相关引用依赖项(即../../../libs/NLog/NLog.dll用于所有引用NLog的Visual Studio项目)
  6. 所有Visual Studio .sln文件都位于第二级(src文件夹),以便在将组件"共享"到消耗组件或产品时不包含它们
  7. 开发人员可以自由组织他们认为合适的源文件,只要源是使用Visual Studio项目的proj*文件夹的子文件(即,proj*文件夹中可以有n个子文件,包含各种源/资源)
  8. 如果Bob正在开发SHARED2组件和PROD1产品,那么在PROD1_SLN存储库中更改SHARED2源(比如属于proj3的源)并提交这些更改是完全合法的.我们不介意是否有人在消费项目的背景下开发了一个库.
  9. 内部开发的组件(SHARED1和SHARED2)通常通过在消费项目(在Visual Studio中加入一个项目的引用,而不是浏览到DLL参考)源包括在内.这允许增强调试(步入库代码),允许Visual Studio在需要重建项目时进行管理(当依赖项被修改时),并允许在需要时修改库(如上面的说明中所述).

问题

  1. 如果Bob正在处理PROD1并且Alice正在使用SHARED1,那么Bob如何知道Alice何时提交对SHARED1的更改.目前,对于Mercurial,Bob被迫在每个子目录中手动拉取和更新.如果他从PROD_SLN repo推送/拉到服务器,他从不知道subrepos的更新.这在Mercurial wiki中有所描述.当Bob从服务器中提取最新的PROD_SLN时,如何通知Bob subrepos的更新?理想情况下,应该通知他(最好在拉动期间),然后必须手动决定他想要更新哪个子目录.

  2. 假设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项目,我的结构不允许这样.鲍勃怎么知道他的两个依赖项有版本冲突?

  3. 如果Bob正在为PROD1设置存储库结构并希望包含SHARED2,那么他如何知道SHARED2需要哪些依赖项?使用我的结构,他必须手动克隆(或在服务器上浏览)SHARED2_SLN repo,并查看libs文件夹,或者在.hgsub文件中达到峰值,以确定需要包含哪些依赖项.理想情况下,这将是自动化的.如果我在我的产品中包含SHARED2,也会自动包含SHARED1和NLog,如果存在与其他依赖项的版本冲突,请通知我(参见上面的问题2).

更大的问题

  1. mercurial是正确的解决方案吗?

  2. 有更好的mercurial结构吗?

  3. 这是subrepos的有效用途(即Mercurial开发人员将subrepos标记为最后的特征)?

  4. 使用mercurial进行依赖管理是否有意义?我们可以使用另一个工具进行依赖关系管理(可能是内部的NuGet提要?).虽然这对于第三方依赖项很有效,但它确实会为内部开发的组件带来麻烦(即如果它们是积极开发的,开发人员必须不断更新feed,我们必须在内部提供它们,并且它不允许消费项目要修改的组件(注8和问题2).

  5. 您是否有更好的Enterprise .NET软件项目解决方案?

参考

我已经阅读了几个SO问题并发现这个问题很有用,但是接受的答案建议使用专用的依赖工具.虽然我喜欢这种工具的功能,但它不允许从消费项目中修改和提交依赖项(参见更大的问题4).

Cla*_*rae 12

这可能不是您正在寻找的答案,但我们最近有使用子回购的Mercurial新手用户的经验,我一直在寻找机会传递我们的经验......

总之,我根据经验提出的建议是:无论Mercurial子回购都有吸引力,不要使用它们.相反,找到一种并排布局目录的方法,并调整构建以应对这种情况.

无论如何吸引人的似乎是将子仓库中的修订与父仓库中的修订捆绑在一起,它只是在实践中不起作用.

在转换的所有准备过程中,我们收到了来自多个不同来源的建议,即子回购是脆弱的并且没有很好地实现 - 但我们仍然继续前进,因为我们想要回购和子回购之间的原子提交.建议 - 或者我对它的理解 - 更多地谈论了原则而不是实际后果.

只有在我们与Mercurial和子回购公司合作之后,我才能真正理解这些建议.这里(来自记忆)是我们遇到的各种问题的例子.

  • 您的用户最终将与更新和合并过程作斗争.
  • 有些人会更新父回购而不是子回购
  • 有些人会从子回购推出,ang .hgsubstate不会得到更新.
  • 您将最终"丢失"在子仓库中进行的修订,因为有人会在合并后设法将.hgsubstate置于不正确的状态.
  • 有些用户会遇到.hgsubstate已经更新但子仓库没有更新的情况,然后你会得到非常神秘的错误消息,并且会花费很多时间来计算出正在发生的事情.
  • 如果你对发布版进行标记和分支,那么如何为父级和子级回购提供正确的指令将会有很多行.(我甚至有一个很好的,温顺的Mercurial专家帮我写指示!)

所有这些事情在专家用户手中都很烦人 - 但是当你向新手用户推出Mercurial时,它们是一场真正的噩梦,也是浪费时间的浪费源头.

所以,我花了很多时间用子仓库进行转换,几周后我们将子仓库转换为回购.因为我们在通过.hgsubstate引用子回购的转换中有大量的历史记录,所以它给我们带来了更复杂的东西.

我只希望我真的很感激早期所有建议的实际后果,例如Mercurial的最后度假胜地页面:

但我需要管理子项目!

再说一次,不要那么肯定.像Mozilla这样具有大量依赖关系的重要项目在没有使用子版本的情况下做得很好.如果不使用subrepos,大多数小型项目几乎肯定会更好.


编辑:关于shell回购的想法

有了免责声明,我对他们没有任何经验......

不,我不认为他们中的很多人都是.您仍然在使用子回购,因此所有相同的用户问题都适用(除非您可以为每个步骤提供包装脚本,当然,除去人类需要提供正确的选项来处理子回购.)

另请注意,您引用的Wiki页面列出了shell repos的一些特定问题:

  • 过度严格跟踪project /和somelib /之间的关系
  • 无法检查或推送项目/如果somelib/source repo成为
  • 缺乏对递归diff,log和的明确定义的支持
  • 状态递归性质令人惊讶

编辑2 - 进行试用,涉及所有用户

我们真正开始意识到我们遇到问题的一点是,一旦多个用户开始提交,拉动和推动 - 包括对子仓库的更改.对我们来说,回应这些问题在当天为时已晚.如果我们早点了解它们,我们可以更轻松,更简单地做出回应.

所以在这一点上,我认为我能提供的最佳建议是建议您在布局刻在一块之前进行项目布局的试运行.

我们离开了全面的审判,直到为时已晚,无法进行更改,即使这样,人们只对父回购进行了更改,而不是子回购 - 所以我们仍然没有看到全貌,直到为时已晚.

换句话说,无论您考虑什么布局,在该布局中创建存储库结构,并让很多人进行编辑.尝试将足够的真实代码放入各种repos/sub-repos中,以便人们可以进行真正的编辑,即使它们是抛出的.

可能的结果:

  • 您可能会发现一切正常 - 在这种情况下,您将花费一些时间来获得确定性.
  • 另一方面,您可能比花时间试图找出结果会更快地发现问题
  • 而且您的用户也会学到很多东西.

  • 至于你从Selenic [最后的度假页面的特点](http://mercurial.selenic.com/wiki/FeaturesOfLastResort#But_I_need_to_have_managed_subprojects.21)的引用,我真的对Selenic的这个陈述有疑问,因为它没有提供任何描述或参考如此大胆的声明.他们如何管理所述依赖项?他们是否与消费产品并行开发了紧密耦合的共享库/模块?他们是否会发布使用共享库的几种不同产品?对于Selenic或该维基页面的作者来说,这些都是真正的修辞问题...... (2认同)