Git 中的供应商分支

Posted

技术标签:

【中文标题】Git 中的供应商分支【英文标题】:Vendor Branches in Git 【发布时间】:2010-10-20 15:58:36 【问题描述】:

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

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

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

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

不过,我似乎无法让它工作。

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

请不要向我解释我应该如何使用子模块或子树合并甚至 SVN:Externals。此线程是the following SO thread 的产物,如果那里遗漏了什么,请务必将其发布在那里。该线程正在尝试获取 了解如何为 Vendor 分支,以及越长、越清晰、越愚蠢的解释,我会越快乐。

【问题讨论】:

刚刚根据您的评论添加了一些想法:如果不能完全解决问题,请随时进一步完善 刚刚对您的要求添加了进一步的想法,但仍然没有明确的答案。很抱歉。 红宝石? Git 与 ruby​​ 无关……它是为 Linux 内核设计的。 Git bash 在我使用 Win32 系统的罕见日子里一直对我很好。 这是话题……你一直在争论 git 与 ruby​​ 相关联。它不是。 Rail 不是红宝石。 您所描述的不是供应商分支。供应商分支是您维护第三方产品的自定义版本的地方,第三方仅向您提供源代码,而不是对其存储库的访问。当您收到来自第三方的更新时,您将其提交到您的供应商分支,然后将他们的更改合并到您的主分支中。 【参考方案1】:

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

只是一个想法;你想要的:

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

这两种方法不兼容:

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

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

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


samgoody 补充道:

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

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

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

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

samgoody 补充道:

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

我不确定 GitHub 的下载最近是否有问题:那篇“Guides: Developing with Submodules”文章确实提到了:

最重要的是:克隆您的 my-awesome-framework 分支的人将毫无问题地拉下您的 my-fantastic-plugin 子模块,因为您已经为子模块注册了公共克隆 URL。命令

$ gh submodule init
$ gh submodule update

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

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

samgoody 提到:

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

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

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

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

【讨论】:

想象一个适用于 Joomla 和 ModX 的 eMap 插件。插件和特定于 Joomla 的代码(它是 Joomla 的一部分,而不是 eMap 的一部分)都是在插件位于 Joomla 内部时开发的。所有路径都是相对的,结构是刚性的,它们必须分布在一起——即使每个项目都有自己的生命周期。我不是最新的 IDE;去年,我们的办公室从 Eclipse 切换到 HTM/php/JS 的 Notepad++,并从 Flex 切换到 AS [生产力得到提高] 的 FD。我错过了什么大事吗? 你的答案:如果项目是相互依赖的,子树合并。否则使用子模块。我需要避免子树和子模块(请参阅问题),并且如果该方法是合理的,我宁愿解决这个需求而不争论太多。在我的情况下,较大的项目必须包括子项目,但反之则不然。原始线程列出了子模块的问题 - 主要是 GitHub 的下载不包括它们(对我来说很重要)并且它们卡在特定的提交上。有什么想法吗? 这是一个非常有趣的答案。我之前没有听说过componentsystem scm 方法之间的比较。这个概念从何而来?即是否有一些开创性的学术论文/博客文章或书籍普及了这些思想?如果是这样,请您提供参考吗? @JW。我在过去使用 ClearCase 的经验中第一次遇到这些概念:***.com/a/1766662/6309 感谢 VonC 的参考。我会尽快详细研究。我想,粗略一看,这些想法似乎源自 IBM 的统一变更管理。 redbooks.ibm.com/redbooks/SG246399/wwhelp/wwhimpl/common/html/… 这是我已添加到阅读列表中的内容。【参考方案2】:

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

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

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

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

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

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

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

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

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

【讨论】:

个人笔记 - ..你说“我不是 Git 大师” - 我注意到你的答案是网站上几乎所有与 Git 相关的 Q' 的公认答案。我非常感谢您的帮助。 ..“VonC(他通常会非常彻底地思考问题)” - 我应该这样认为。一个拥有世界专家贡献的网站,到底是如何获得 25,000 多分的?!我敬畏!我也感谢他的帮助。你们好棒。现在,如果我能让这个工作...... :) "..我会使用两个 Git repos" - 我正在尝试这个,但是(我是新手)无法理解。从这篇文章中,我了解到要更新供应商项目,我应该将他们最新的提交子树合并到父项,创建父项的一个名为“供应商”的分支,然后进行更改。他们将这些更改从我的“供应商”分支引入到他们的项目中。我没有意识到这是可行的,也不明白把它变成一个分支的意义。其他帖子也没有避免子树合并吗? 请不要生气,但请告诉我是否有地方可以查看完整的逐行工作流程。 (一个理论例子)[1。 clone git://project.git 2. merge branch origin 3. commit origin master etc.] 非常感谢。 Scott Chacon 在section on Subtree Merging In Chapter 9 of the Pro Git (2009) book 中对使用子树合并所涉及的工作流程进行了很好的解释。也许这会有所帮助。【参考方案3】:

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

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

https://www.roe.ch/Git_Reference

部分供应商分支模式

【讨论】:

这应该是公认的答案...... OP 要求解决方案,而人们提供的替代方案并不真正符合要求。我为 OP 感到抱歉,因为这是清晰而简单的解决方案。

以上是关于Git 中的供应商分支的主要内容,如果未能解决你的问题,请参考以下文章

Git - 供应商文件夹修改 - .gitignore?

如何清理 CVS 供应商分支导入?

PHPStorm、供应商和多个 Git 根

在 SVN 中处理供应商分支的最佳方法是啥?

优先队列式分支限界法-最小重量机器设计问题

将本地新工程与 git 关联