Hg 子存储库依赖项

发布于 2024-10-31 11:00:15 字数 2179 浏览 0 评论 0原文

过去存在一些关于 Hg 子存储库依赖关系的问题(此处此处)但接受的答案似乎并不能解决我的问题。

我的一个项目有4个依赖:A、B、C、D。D依赖于A、B和C; B 和 C 依赖于 A:

A、B、C、D 的依赖图

我想使用 Hg sub-存储库来存储它们,以便我可以跟踪它们所依赖的每个版本。这是因为,当我在这个项目中使用 A、B、C 和 D 时,其他项目将只需要 A 和 B。因此,B 和 C 必须独立于 D 跟踪它们需要的 A 版本。同时,在我的应用程序中,给定版本 D 引用的 B 和 C 版本必须始终使用与 D 的给定版本引用的 A 版本相同的版本。给定的 D 版本(否则它会在运行时崩溃)。我真正想要的是允许它们在同一目录中作为兄弟姐妹互相引用 - 即 D 的 .hgsub 看起来像下面这样,而 B 和 C 看起来像第一行。

..\A = https:(central kiln repo)\A
..\B = https:(central kiln repo)\B
..\C = https:(central kiln repo)\C

然而,这似乎不起作用:我可以明白为什么(很容易给人们足够的绳子来吊死自己),但它是一种耻辱,因为我认为这是解决我的依赖关系的最巧妙的解决方案。我已经阅读了一些建议的解决方案,我将快速概述这些解决方案以及为什么它们对我不起作用:

  1. 将副本作为嵌套子目录,将它们引用为 Hg 子存储库。这会产生以下目录结构(我已经删除了 A、B、C、B\A、C\A 的主要副本,因为我可以接受引用 \D 内的副本):

    • project\(所有主项目文件)
    • 项目\D
    • 项目\D\A
    • 项目\D\B
    • 项目\D\B\A
    • 项目\D\C
    • 项目\D\C\A

    这种方法的问题:

    • 我现在在磁盘上有 3 个 A 副本,所有这些副本都可以具有独立的修改,必须在推送到中央存储库之前同步和合并这些修改。
    • 我必须使用其他机制来确保 B、C 和 D 引用 A 的同一版本(例如 D 可以使用 v1,而 D\B 可以使用 v2)
  2. A 变体:使用上述内容,但指定.hgsub 的 RHS 指向父副本中的副本(即 B 和 C 应该具有下面的 .hgsub):

    <前><代码>A = ..\A

    这种方法的问题:

    • 我的磁盘上仍然有三个副本
    • 第一次克隆 B 或 C 时,它将尝试从“..\A”递归地提取 A 的引用版本,该版本可能不存在,可能会导致错误。如果它不存在,则不会提供有关应该在哪里找到存储库的任何线索。
    • 当我递归推送更改时,D\B\A 中的更改不会进入共享中央存储库;他们只是被推到D\A。因此,如果我连续推送两次,我可以保证所有更改都会正确传播,但这完全是一个谎言。
    • 同样,如果我执行(手动)递归拉取,我必须确保顺序正确才能获取最新更改(即在拉取 D\B\A 之前拉取 D\A)
  3. 使用符号链接将文件夹 \D\B\A 指向 D\A 等

    这种方法的问题:

    • 符号链接无法在 Hg 存储库本身中进行编码,因此每次团队成员克隆存储库时,他们都必须手动/使用脚本重新创建符号链接。这可能是可以接受的,但我更喜欢更好的解决方案。另外(个人喜好)我发现符号链接非常不直观。

这些是最好的可用解决方案吗?我最初的 .hgsub (见顶部)是一个白日梦,是否有充分的理由,或者有什么方法可以请求/实施此更改?

已更新以更好地解释 A、B、C、D 的更广泛用法

There have been a couple of questions about Hg sub-repo dependencies in the past (here and here) but the accepted answers don't seem to address the problem for me.

A project of mine has 4 dependencies: A, B, C, D. D is dependent on A, B and C; and B and C are dependent on A:

dependency graph of A,B,C,D

I want to use Hg sub-repositories to store them so I can track what version of each they rely on. This is because, while I am using A,B,C and D in this project, other projects will require just A and B. Therefore B and C must track what version of A they need independently of D. At the same time, in my application the versions of B and C referenced by a given version of D must always use the same version of A as that referenced by the given version of D (otherwise it will just fall over at runtime). What I really want is to allow them to reference each other as siblings in the same directory - i.e. D's .hgsub would look like the following, and B and C's would look like the first line.

..\A = https:(central kiln repo)\A
..\B = https:(central kiln repo)\B
..\C = https:(central kiln repo)\C

However this doesn't seem to work: I can see why (it'd be easy to give people enough rope to hang themselves with) but its a shame as I think its the neatest solution to my dependencies. I've read a few suggested solutions which I'll quickly outline and why they don't work for me:

  1. Include copies as nested sub-directories, reference these as Hg sub-repositories. This yields the following directory structure (I've removed the primary copies of A, B, C, B\A, C\A as I can accept referencing the copies inside \D instead):

    • project\ (all main project files)
    • project\D
    • project\D\A
    • project\D\B
    • project\D\B\A
    • project\D\C
    • project\D\C\A

    Problems with this approach:

    • I now have 3 copies of A on disk, all of which could have independent modifications which must be synced and merged before pushing to a central repo.
    • I have to use other mechanisms to ensure that B, C and D are referencing the same version of A (e.g. D could use v1 while D\B could use v2)
  2. A variation: use the above but specify the RHS of the .hgsub to point to a copy in the parent copy (i.e. B and C should have the .hgsub below):

    A = ..\A
    

    Problems with this approach:

    • I still have three copies on disk
    • The first time I clone B or C it will attempt to recursively pull the referenced version of A from "..\A", which may not exist, presumably causing an error. If it doesn't exist it gives no clue as to where the repo should be found.
    • When I do a recursive push of changes, the changes in D\B\A do not go into the shared central repo; they just get pushed to D\A instead. So if I push twice in a row I can guarantee that all changes will have propagated correctly, but this is quite a fudge.
    • Similarly if I do a (manual) recursive pull, I have to get the order right to get the latest changes (i.e. pull D\A before I pull D\B\A)
  3. Use symlinks to point folder \D\B\A to D\A etc.

    Problems with this approach:

    • symlinks cannot be encoded in the Hg repo itself so every time a team member clones the repo, they have to manually/with a script re-create the symlinks. This may be acceptable but I'd prefer a better solution. Also (personal preference) I find symlinks highly unintuitive.

Are these the best available solutions? Is there a good reason why my initial .hgsub (see top) is a pipe-dream, or is there a way I can request/implement this change?

UPDATED to better explain the wider usage of A,B,C,D

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

乖乖兔^ω^ 2024-11-07 11:00:16

不要尝试通过 Mercurial(或任何 SCM)来管理依赖项,而是尝试使用依赖项管理工具,例如 Apache Ivy

使用基于 Ivy 的方法,您没有任何子存储库,您只有项目 A、B、C 和 D。A 生成一个工件(例如 .jar、.so 或 .dll 等),即使用版本发布到工件存储库(基本上是保存构建工件的地方)。然后,项目 B 和 C 可以依赖于 A 的特定版本(通过每个项目中的 ivy.xml 文件控制),Ivy 将从工件存储库中检索该版本。项目 B 和 C 还会生成发布到您的存储库的工件。项目 D 依赖于 B 和 C,并且 Ivy 可以被告知以传递方式检索依赖项,这意味着它将获得 B、C 和 A 的工件(因为它们依赖于 A)。

类似的方法可以用于 Apache MavenGradle(后面使用了ivy)

主要优点是:

  • 它可以非常清楚地显示项目正在使用的每个组件的版本(有时人们会忘记检查.hgsub,所以他们不知道自己正在使用子存储库),
  • 这使得无法更改依赖项目(因为您正在使用工件,而不是代码)
  • ,并且它使您不必重建依赖项目并且不确定您使用的是什么版本。
  • 使您免于拥有被其他项目使用的多个冗余项目副本。

编辑:类似的答案,但略有不同的旋转 使用 Mercurial 和 Eclipse 的项目功能子模块的最佳实践?

Instead of trying to manage your dependencies via Mercurial (or with any SCM for that matter), try using a dependency management tool instead, such as Apache Ivy.

Using an Ivy based approach, you don't have any sub-repos, you would just have projects A, B, C and D. A produces an artifact (e.g. a .jar, .so or .dll, etc), which is published into an artifact repository (basically a place where you keep your build artefacts) with a version. Projects B and C can then depend on a specific version of A (controlled via a ivy.xml file in each project) which Ivy will retrieve from the artifact repository. Projects B and C also produce artefacts that are published to your repository. Project D depends on B and C and Ivy can be told to retrieve the dependencies transitively, which means it will get the artifacts for B, C and A (because they depend on A).

A similar approach can be used with Apache Maven and Gradle (the later uses Ivy)

The main advantages are that:

  • it makes it very clear what versions of each component a project is using (sometimes people forget to check .hgsub, so they don't know they are working with subrepos),
  • it makes it impossible to change a dependant project (as you are working with artifacts, not code)
  • and it saves you from having to rebuild dependent projects and being unsure of what version you are using.
  • saves you from having multiple redundant copies of projects that are used by other projects.

EDIT: Similar answer with a slightly different spin at Best Practices for Project Feature Sub-Modules with Mercurial and Eclipse?

青春有你 2024-11-07 11:00:16

你说你想跟踪它们各自依赖的版本,但你也会对 B、C 和 D 之间共享的 A 的单个副本感到满意。这些是互斥的 - 对于 A 的单个副本,对 A 的任何更改都会导致 B、C 和 D 中每个的 .hgsub 发生更改,因此版本控制不具有独立性(因为所有 B、C 和 D 都会在 A 更改后提交)。

拥有单独的副本也会很尴尬。如果您所做的更改同时影响 A 的 B 副本和 C 的副本,然后尝试推送整个结构,则对(例如)B 的更改将成功,但对 C 的更改将失败,因为它们需要与您刚刚推送的更改合并B、避免产生新的头。这将是一个痛苦。

我这样做的方法(也许还有更好的方法)是创建一个包含 A、B 和 C 子存储库的 D 存储库。B 和 C 中的每一个都会有一些未跟踪的 A 位置文件(系统会提示您通过后克隆 hook 进入),告诉您的构建系统在哪里寻找其一个存储库。这具有工作的优点,但你失去了跟踪 {B, C} 和 A 的并发版本的系统的便利性。同样,你可以使用由钩子更新的 B 或 C 中每个的 A 版本文件手动执行此操作,通过钩子读取,你可以做到这一点,但我认为不可能使用 hg 中的 subrepos 实现。我的建议实际上可以归结为实现您自己的简化子存储库系统。

You say you want to track which version they each rely on but you'd also be happy with a single copy of A shared between B, C and D. These are mutually exclusive - with a single copy of A, any change to A will cause a change in the .hgsub of each of B, C and D, so there is no independence in the versioning (as all of B, C and D will commit after a change to A).

Having separate copies will be awkward too. If you make a change that affects both B's copy of A and C's copy then attempt to push the whole structure, the changes to (say) B will succeed but the changes to C will fail because they require merging with the changes you just pushed from B, to avoid creating new heads. And that will be a pain.

The way I would do this (and maybe there are better ways) would be to create a D repo with subrepos of A, B and C. Each of B and C would have some untracked A-location file (which you're prompted to enter via a post-clone hook), telling your build system where to look for its A repository. This has the advantage of working but you lose the convenience of a system which tracks concurrent versions of {B, C} and A. Again, you could do this manually with an A-version file in each of B or C updated by a hook, read from by a hook, and you could make that work, but I don't think it's possible using the subrepos implementation in hg. My suggestions really boil down to implementing a simplified subrepo system of your own.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文