33

Git 项目中有第二个项目,其内容正在独立处理。

子模块不能用于较小的模块,因为当用户尝试克隆或下载“父”时,甚至必须包含子项目。

不能使用子树合并,因为子项目正在积极开发中,并且子树合并使得将这些更新合并回原始项目非常困难。

我被告知该解决方案在 SVN 世界中被称为“供应商分支”,并且它在 Git 中非常简单,甚至不需要寻址。网络上的半生不熟的教程比比皆是。

尽管如此,我似乎无法让它工作。

有人可以请(非常好吗?)解释我如何创建一个结构,使一个项目存在于另一个项目中,并且两者都可以从同一个工作目录中开发和更新。理想情况下[或者更确切地说:如果不支持,这非常重要]当客户端尝试下载“父”项目时,应该自动为他提供最新版本的子项目。

请不要向我解释我应该如何使用子模块或子树合并甚至 SVN:Externals。该线程是以下 SO 线程的产物,如果那里遗漏了什么,请在此处发布。该线程试图了解如何使用 Vendor 分支,并且我收到的解释越长、越清晰、越愚蠢,我会越快乐。

4

3 回答 3

40

我认为子模块是“供应商分支”的必经之路。
以下是您应该如何使用 submod... 嗯,开个玩笑。

只是一个想法; 你要:

  • 在同一目录中开发主项目和子项目(这称为“系统方法”:您开发、标记和合并所有系统)
  • 或将您的子项目视为“供应商分支”(这是一个允许您访问供应商外部组件或“文件集”的明确定义版本的分支,并且仅使用新的版本该外部组件的每个版本:这称为“组件方法”,所有系统都被视为自行开发的独立组件的集合)

这两种方法不兼容:

  • 第一个策略与子树合并兼容:您同时在项目和子项目上工作。
  • 第二个用于子模块,但子模块用于定义配置(您需要工作的标记列表):每个 git 子模块,与 svn:externals 不同,都固定到特定的提交 id,这就是允许您定义配置(如 S C M:“软件配置管理”)

我喜欢第二种方法,因为大多数时候,当你有一个项目和一个子项目时,它们的生命周期是不同的(它们的开发节奏不同,没有同时标记在一起,也没有同名) .

在您的问题中真正阻止这种方法(“基于组件”)的是“两者都可以从同一个工作目录中开发和更新”部分。
我真的敦促您重新考虑该要求,因为大多数 IDE 完全能够处理多个“源”目录,并且子项目开发可以在其自己的专用环境中完成。


samgoody 补充道:

想象一下适用于 Joomla 和 ModX 的 eMap 插件。插件和特定于 Joomla 的代码(它是 Joomla 的一部分,而不是 eMap 的一部分)都是在插件位于 Joomla 内部时开发的。所有路径都是相对的,结构是刚性的,它们必须分布在一起——即使每个项目都有自己的生命周期。

如果我理解正确,您处于开发环境(您正在处理的文件集)与分发环境(在发布平台上复制相同的文件集)完全相同的配置中

这一切都是为了一个粒度问题:

  • 如果两组文件不能单独存在,那么它们应该被视为一个大项目(和子树合并),但这会迫使它们被标记并合并为一个。- 如果一个依赖于另一个(可以单独开发),那么它们应该在自己的 Git 存储库和项目中,第一个依赖于第二个作为子模块的特定提交:如果子模块是在第一个组件的右子树中定义,所有相对路径都受到尊重。

samgoody 补充道:

原始线程列出了子模块的问题 - 主要是 GitHub 的下载不包括它们(对我来说很重要)并且它们卡在特定的提交上。

我不确定 GitHub 的下载最近是否存在问题:“指南:使用子模块开发”文章确实提到:

最重要的是:克隆你的my-awesome-frameworkfork 的人将没有问题拉下你的my-fantastic-plugin子模块,因为你已经为子模块注册了公共克隆 URL。命令

$ gh submodule init
$ gh submodule update

将子模块拉入当前存储库。

至于“他们卡在特定的提交上”:这是子模块的全部要点,允许您使用配置(组件的标记版本列表)而不是最新的可能不稳定的文件集。

samgoody 提到:

我需要避免使用子树和子模块(请参阅问题),如果方法合理,我宁愿解决这个需求而不争论太多

您的要求是完全合理的,我不想评判其合理性:我之前的回答只是为了提供更大的上下文并尝试说明通用 SCM 工具通常可用的选项。

子树合并应该是这里的答案,但意味着只合并为主项目的文件提交,而不是子项目的提交。如果您可以管理这种部分合并,我认为这是正确的道路。

但是,我看不到不使用子树合并或子模块的本地 Git 方式来做你想做的事。
我希望真正的 Git 大师会在这里发布更充分的答案。

于 2009-04-20T20:28:28.610 回答
7

在我回到山上之前,我终于可以上网几个小时了。我们会看看我是否有什么可以澄清你的情况。

我(可能过于简单化)的理解是,您有(场外)供应商为您的项目开发插件,而您的(内部)团队正在使用外部来源的框架为您的主要项目开发代码。供应商不会更改您的代码,并且可能不需要您进行前沿开发,但确实需要您的稳定代码来开发和测试他们的工作。您的团队不会对框架进行更改,但有时会为插件做出更改。

  1. 像 VonC(他通常会非常彻底地思考问题)一样,我认为 Git 并不完全适合您的要求。和他一样,我认为使用子树合并模式是最合适的。我不是 Git 专家,但我成功地让 Git 适应了广泛的需求。也许 Git 不能满足您的需求:

    • SVN 会让你在一个中拥有多个 repos,这对你来说似乎很重要。我认为这意味着使用外部或供应商分支模式来接近你想要的。

    • Mercurial 有一个扩展程序Forest,用于使用嵌套存储库,这似乎更适合您的心理模型。我在 15 个月前选择了 Git 而不是 Mercurial,但 HG 很稳定,而且在许多用途上我认为它可以与 Git 相媲美。我不知道扩展的稳定性如何。

  2. 如果我遇到你的情况,我会使用两个 Git 存储库——一个用于插件,一个用于 MainProject。供应商将在 Plugin repo 中进行开发,并将拥有一个发布分支,他们将插件的当前版本拉入其中,而无需开发环境的其余部分。该分支将作为供应商分支拉入 MainProject 存储库,然后合并到您的主开发分支中。 当您的团队对插件进行更改时,他们会在您的主要开发分支的功能分支中开发它,并将其作为补丁提交给供应商存储库。 这为您提供了一个非常干净的工作流程,相对容易设置和学习,同时保持开发历史隔离。

    我并不是要争论,而只是说这是 Git 最适合我对您的情况的理解。设置它的最简单方法是使用子树合并,但这不会在两个方向上运行更改,这是我反对使用该模式的原因。

  3. 如果您的团队真的积极参与插件开发,或者您真的希望将项目和插件的开发历史集成到一个 Git 存储库中,那么只需使用一个 Git 存储库。您可以按照此处的说明,不时提取插件及其历史记录以供供应商使用。这可能会给您带来比您想要的更少的封装,但 Git 并不是为封装而设计的——Git 的数据结构基于跟踪整个项目中的更改。

也许我误解了你的情况,这些都不适用。如果是这样我道歉。感谢您和 VonC 制定的详细信息,这些信息填补了我最初在试图理解您的问题时遇到的许多漏洞。

于 2009-04-22T20:53:08.330 回答
1

如果您只查找原始问题的标题:

使用 git 的供应商分支模式的一个很好的模板已启用

https://www.roe.ch/Git_Reference

部分供应商分支模式

于 2018-01-17T13:42:20.923 回答