什么时候使用git子树?

Ler*_*rve 57 git git-subtree

有什么问题可以git subtree解决?何时以及为什么要使用该功能?

我已经读过它用于存储库分离.但为什么我不只是创建两个独立的存储库而不是将两个不相关的存储库合二为一?

这个GitHub教程解释了如何执行Git子树合并.

我知道如何使用它,但不知道何时(用例)及其原因,以及它与之相关的方式git submodule.当我依赖于另一个项目或库时,我会使用子模块.

Mat*_*ers 36

当您在上下文中使用术语"子树"时,您应该小心地注意到您正在谈论的内容,git因为这里实际上有两个独立但相关的主题:

git-subtreegit子树合并策略.

TL; DR

两个子树相关概念都有效地允许您在一个中管理多个存储库.与git-submodule相反,git-submodule只有元数据以.gitmodules的形式存储在根存储库中,您必须单独管理外部存储库.

更多细节

git子树合并策略基本上是使用您引用的命令的更多手动方法.

git-subtree是一个包装器shell脚本,以方便更自然的语法.这实际上仍然是contribgit 的一部分,并没有与通常的手册页完全集成.而是将文档存储在脚本的旁边.

这是使用信息:

NAME
----
git-subtree - Merge subtrees together and split repository into subtrees


SYNOPSIS
--------
[verse]
'git subtree' add   -P <prefix> <commit>
'git subtree' add   -P <prefix> <repository> <ref>
'git subtree' pull  -P <prefix> <repository> <ref>
'git subtree' push  -P <prefix> <repository> <ref>
'git subtree' merge -P <prefix> <commit>
'git subtree' split -P <prefix> [OPTIONS] [<commit>]
Run Code Online (Sandbox Code Playgroud)

关于子树的问题,我遇到了相当多的资源,因为我正在计划编写自己的博客文章.如果我这样做,我会更新这篇文章,但现在这里有一些与手头问题相关的信息:

多少你正在寻找上可以找到什么样的这个Atlassian的博客尼古拉·保卢奇以下相关说明:

为什么使用子树而不是子模块?

您可能会发现subtree使用的原因有以下几种:

  • 简单管理简单的工作流程.
  • git支持旧版本(甚至之前v1.5.2).
  • 子项目的代码clone在超级项目完成后立即可用.
  • subtree不要求您的存储库用户学习任何新东西,他们可以忽略您subtree用来管理依赖项的事实.
  • subtree不会像添加submodules(即 .gitmodule)那样添加新的元数据文件.
  • 可以修改模块的内容,而无需在其他位置具有依赖项的单独存储库副本.

在我看来,缺点是可以接受的:

  • 您必须了解新的合并策略(即subtree).
  • upstream为子项目贡献代码稍微复杂一些.
  • 在提交中不混合超级和子项目代码的责任在于你.

我同意其中的大部分内容.我会建议查看文章,因为它有一些常见用法.

你可能已经注意到他还在这里写了一篇后续文章,他提到了一个重要的细节,这种方法被这种方法所取代......

git-subtree 目前无法包含遥控器!

这种短视可能是因为人们经常在处理子树时手动添加遥控器,但这也不存储在git中.作者详细介绍了他编写的补丁,用于将此元数据添加到git-subtree已生成的提交中.直到这使它成为官方git主线,你可以通过修改提交消息或将其存储在另一个提交中来做类似的事情.

我也发现这篇博文也非常有用.作者添加了他调用git-stree混合的第三个子树方法.这篇文章值得一读,因为他在比较这三种方法方面做得非常好.他对自己所做和不喜欢的事情给出了个人意见,并解释了为什么他创造了第三种方法.

附加功能

闭幕思考

本主题显示git功能错过标记时可能发生的功能和分段.

我个人已经厌倦了,git-submodule因为我发现让贡献者理解更加困惑.我还希望在我的项目中管理所有依赖项,以便在不尝试管理多个存储库的情况下实现易于重现的环境.git-submodule然而,目前更为人所知,所以很明显要注意它并且取决于你的观众可能会影响你的决定.

  • _git-stree_ 的作者在同一篇博客文章中表示,他自 2016 年以来一直支持 [git-subrepo](https://github.com/ingydotnet/git-subrepo)。 (2认同)

cfi*_*cfi 9

第一个:我相信你的问题往往得到强烈的自以为是的答案,可能在这里被视为偏离主题.然而,我不喜欢那个SO政策,并且会把话题放在主题上,所以我喜欢回答并希望其他人也这样做.

在您指向的GitHub教程中,有一个如何使用子树合并策略的链接,该策略给出了优缺点的观点:

将子树合并与子模块进行比较

使用子树合并的好处是它可以减少存储库用户管理负担.它适用于较旧的(在Git v1.5.2之前)客户端,并且您在克隆之后就拥有了代码.

但是,如果使用子模块,则可以选择不传输子模块对象.这可能是子树合并的问题.

此外,如果您对其他项目进行更改,如果您只使用子模块,则更容易提交更改.

以下是基于以上观点的观点:

我经常与那些不是常规git用户的人(=提交者)合作,有些人仍然(并将永远)与版本控制斗争.教育他们如何使用子模块合并策略基本上是不可能的.它涉及额外遥控器的概念,关于合并,分支,然后将它们全部混合到一个工作流程中.从上游拉出并向上游推进是一个两阶段过程.由于分支很难为他们理解,这一切都是没有希望的.

对于子模块来说,它们仍然过于复杂(叹气),但它更容易理解:它只是一个回购中的回购(他们熟悉层次结构),你可以照常进行推拉.

为子模块工作流程提供简单的包装器脚本更容易实现.

对于具有许多子回购的大型超级回购,选择不克隆某些子回购数据的点是子模块的重要优点.我们可以根据工作要求和磁盘空间使用情况对此进行限制.

访问控制可能不同.尚未遇到此问题,但如果不同的存储库需要不同的访问控制,有效地禁止某些用户使用某些子存储库,我想知道使用子模块方法是否更容易实现.

就个人而言,我还没决定要自己使用什么.所以我分享你的困惑:o]

  • 尽管有矛盾,但这个答案是我见过的最坚决的答案,因为它是唯一的答案,也是自我实现的预言。愤怒的叹息,毁灭者的态度对别人的学习能力,这是一个非常傲慢的答案。您对政策的看法可能属于Meta,可能会对您有所帮助。答案本身,除了自我服务之外,还是相当不错的。 (3认同)
  • @vgoff:你的批评是正确的。抱歉,看起来很傲慢 - 这只是超过 15 年的工作经验,这些人在不同的版本控制系统中接受过不同人的培训,并且仍然将文本文件复制到大量的“.backup.&lt;timestamp&gt;”中。我想我一开始就说得很清楚,这将是固执己见的。希望其他人能够提供更真实的见解,令我惊讶的是还没有人这样做。 (3认同)

SH'*_*SH' 7

基本上 Git-subtree 是 Git-submodule 方法的替代方案:有很多缺点,或者我想说的是,在使用 git-submodules 时你需要非常小心。例如,当您有“一个”存储库并且在“一个”内部时,您使用子模块添加了另一个名为“两个”的存储库。您需要注意的事项:

  • 当您在“two”中更改某些内容时,您需要提交并推送到“two”中,如果您位于顶级目录(即在“one”中),则您的更改不会突出显示。

  • 当未知用户尝试克隆您的“一个”存储库时,在克隆“一个”之后,该用户需要更新子模块以获取“两个”存储库

这些是一些要点,为了更好地理解,我建议您观看此视频:https : //www.youtube.com/watch?v=UQvXst5I41I

  • 为了克服这些问题,发明了子树方法。要获得有关 git-subtree 的基础知识,请查看以下内容:https : //www.youtube.com/watch?v=t3Qhon7burE

  • 我发现与子模块相比,子树方法更可靠和实用:)(我非常初学者说这​​些事情)

干杯!


Mar*_*ski 6

我们有一个真实的用例,其中 git subtree 是一种救赎:

我们公司的主要产品是高度模块化的,并在不同的存储库中的多个项目中开发。所有模块都有各自的路线图。整个产品由具体版本的所有模块组成。

与此同时,整个产品的具体版本是为我们的每个客户定制的——每个模块都有单独的分支。有时必须同时在多个项目中进行定制 ( cross-module customization)。

为了为定制产品提供单独的产品生命周期(维护、功能分支),我们引入了 git subtree。我们有一个用于所有自定义模块的 git-subtree 存储库。我们的定制是每天“git subtree push”回到所有原始存储库到定制分支。

像这样,我们避免管理许多 repos 和许多分支。git-subtree 数倍地提高了我们的生产力!

更新

有关发布到评论的解决方案的更多详细信息:

我们创建了一个全新的存储库。然后我们将每个具有客户端分支的项目作为子树添加到该新存储库中。我们有一个 jenkins 工作,定期将原始存储库的主更改推送到客户端分支。我们只使用带有功能和维护分支的典型 git 流来处理“客户端存储库”。

我们的“客户”存储库还构建了我们也为这个特定客户改编的脚本。

然而,提出的解决方案存在缺陷。

随着我们离产品的主要核心开发越来越远,针对特定客户的可能升级变得越来越困难。在我们的例子中,子树之前的项目状态已经是一条主路径,所以子树至少引入了引入默认 git 流程的顺序和可能性。

  • 我想建议您将评论中的附加信息合并到您的答案中;他们肯定会让这是一个更好的答案。 (2认同)