git subtree
解决什么问题?什么时候以及为什么要使用该功能?
我读过它用于存储库分离。但是,为什么我不只是创建两个独立的存储库,而不是将两个不相关的存储库合并为一个?
这个GitHub教程解释了如何执行Git子树合并。
我有点知道如何使用它,但是不知道何时(用例),原因以及与它的关系git submodule
。当我依赖于另一个项目或库时,我将使用子模块。
git subtree
解决什么问题?什么时候以及为什么要使用该功能?
我读过它用于存储库分离。但是,为什么我不只是创建两个独立的存储库,而不是将两个不相关的存储库合并为一个?
这个GitHub教程解释了如何执行Git子树合并。
我有点知道如何使用它,但是不知道何时(用例),原因以及与它的关系git submodule
。当我依赖于另一个项目或库时,我将使用子模块。
submodule
和subtree
都或多或少实现其纳入相关项目同样的目标,唯一的区别是,submodule
可能会有点不太透明的和更新的子模块是一个两步操作和的缺点subtree
是,提交消息会在两个项目之间混合在一起吗?
subtree
一分为二,并且在依赖项中引入了错误,则subtree
可以在引入了该错误的中找到确切的提交。使用子模块,您将只发现submodule
引起该错误的提交,如果您想快速查找submodule
主项目中导致该错误的提交,则您就是SOL 。
Answers:
在上下文中使用“子树”一词时,您应该小心地明确指出您在说什么,git
因为这里实际上有两个独立但相关的主题:
两种与子树相关的概念都可以有效地使您在一个仓库中管理多个仓库。与git-submodule相比,在根存储库中仅存储元数据,而git-submodule则采用.gitmodules的形式,因此您必须分别管理外部存储库。
git子树合并策略基本上是使用您引用的命令的更手动的方法。
git-subtree是一个包装程序外壳程序脚本,用于促进更自然的语法。实际上,这仍然是contrib
git的一部分,没有与常规手册页完全集成到git中。而是将文档与脚本一起存储。
这是用法信息:
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>]
当我计划编写自己的博客文章时,我遇到了很多有关子树的资源。如果我愿意的话,我将更新这篇文章,但现在这里有一些有关手头问题的信息:
多少你正在寻找上可以找到什么样的这个Atlassian的博客由尼古拉·保卢奇的相关部分如下:
为什么使用子树而不是子模块?
您可能会发现
subtree
更好使用的原因有几个:
- 简单工作流程的管理很容易。
git
支持的旧版本(甚至在之前v1.5.2
)。clone
超级项目完成后,即可使用子项目的代码。subtree
不需要您存储库的用户学习任何新知识,他们可以忽略您subtree
用来管理依赖项的事实。subtree
不会像submodules
那样 添加新的元数据文件.gitmodule
。- 可以修改模块的内容,而无需在其他地方具有依赖项的单独存储库副本。
我认为缺点是可以接受的:
- 您必须了解一种新的合并策略(例如
subtree
)。upstream
向子项目回发代码稍微复杂一些。- 在提交中不混合上层项目代码和下层项目代码的责任在于您。
我也很同意这一点。我建议您检查一下这篇文章,了解它的一些常用用法。
您可能已经注意到,他还在这里写了一篇后续文章,其中提到了此方法遗漏的重要细节...
git-subtree
目前无法包含遥控器!
目光短浅的原因可能是由于人们在处理子树时经常手动添加一个远程对象,但这也没有存储在git中。作者详细介绍了他编写的补丁程序,用于将该元数据添加到git-subtree
已经生成的提交中。在此之前,您可以通过修改提交消息或将其存储在另一个提交中来做类似的事情。
我也发现这篇博客文章也很有帮助。作者将他调用的第三个子树方法添加git-stree
到混合中。这篇文章值得一读,因为他在比较这三种方法方面做得很好。他给出了自己对做什么和不喜欢做什么的个人看法,并解释了为什么他创建了第三种方法。
本主题展示了git
当功能仅丢失标记时的功能以及可能发生的细分。
我个人git-submodule
对此很反感,因为我发现它使贡献者难以理解。我还更喜欢在项目中管理所有依赖项,以提供易于重现的环境,而无需尝试管理多个存储库。git-submodule
但是,当前它的知名度要高得多,因此意识到这一点并取决于可能会影响您决定的听众显然是一件好事。
首先:我相信您的问题容易得到有力的答案,在这里可能被认为是题外话。但是,我不喜欢这样的SO政策,并且会稍微超出话题的边界,因此我想回答,并希望其他人也这样做。
在您所指向的GitHub教程上,有一个指向如何使用子树合并策略的链接,该链接给出了优点/缺点的观点:
比较子树与子模块的合并
使用子树合并的好处是,它需要来自存储库用户的较少管理负担。它适用于较旧的客户端(在Git v1.5.2之前),克隆后您便拥有了代码。
但是,如果您使用子模块,则可以选择不传输子模块对象。这可能与子树合并有关。
另外,如果您对另一个项目进行了更改,则仅使用子模块就更容易提交更改。
基于以上几点,这是我的观点:
我经常与不是常规git用户的人们(= committers)一起工作,有些人(并且将永远)与版本控制作斗争。对他们进行有关如何使用子模块合并策略的教育基本上是不可能的。它涉及附加遥控器的概念,即合并,分支,然后将其全部混合到一个工作流程中。从上游拉动和向上游推动是一个分为两个阶段的过程。由于分支机构很难为他们所理解,所以这一切都是无望的。
对于子模块,对于他们来说仍然太复杂(叹息),但更容易理解:它只是一个回购中的一个回购(他们熟悉层次结构),您可以照常进行推送和拉取。
提供简单的包装脚本对于子模块工作流来说更容易。
对于具有许多子存储库的大型超级存储库,选择不克隆某些子存储库的数据是该子模块的重要优势。我们可以根据工作要求和磁盘空间使用量来限制它。
访问控制可能有所不同。还没有这个问题,但是如果不同的存储库需要不同的访问控制,从而有效地禁止某些用户访问某些子存储库,我想知道使用子模块方法是否更容易做到这一点。
就我个人而言,我不确定自己该怎么用。因此,我与您分享困惑:o]
.backup.<timestamp>
。我想我一开始就明确指出了这一点。希望其他人能够提供更多的事实见解,令我惊讶的是,还没有人感到惊讶。
submodule
是合并使用的库的不赞成使用的旧方法,subtree
而是新的有效方法吗?
read-tree
(并且无论如何分支/合并/远程)。submodules
添加于
我们有一个真实的用例,其中git子树是救恩:
我们公司的主要产品是高模块化的,并在单独的存储库中的多个项目中开发。所有模块都有各自的路线图。整个产品由具体版本的所有模块组成。
同时,我们为每个客户定制了整个产品的具体版本-每个模块都有单独的分支。有时必须一次在多个项目中进行自定义(cross-module customization
)。
为了为定制产品提供单独的产品生命周期(维护,功能分支),我们引入了git子树。我们为所有自定义模块提供了一个git-subtree存储库。我们的定制是每天将所有原始存储库“ git子树推送”回到定制分支。
这样,我们避免管理许多回购和分支。git-subtree多次提高了我们的生产力!
更新
有关发布到评论的解决方案的更多详细信息:
我们创建了一个全新的存储库。然后,我们将每个具有客户端分支的项目添加到该新仓库中,作为子树。我们有一个詹金斯(Jenkins)工作,正在将对原始存储库的主更改定期推回客户分支。我们仅使用带有功能和维护分支的典型git flow与“客户回购”合作。
我们的“客户”存储库还构建了一些脚本,我们也对该脚本进行了调整。
但是,存在提出的解决方案的陷阱。
随着我们离产品的主要核心开发越来越远,对该特定客户进行可能的升级变得越来越困难。在我们的例子中,在子树已经不是主要路径之前,项目状态还可以,所以子树至少引入了顺序和引入默认git flow的可能性。
基本上,Git子树是Git子模块方法的替代方案:有很多缺点,或者我想说,使用git子模块时需要非常小心。例如,当您有“一个”存储库,而在“一个”内部时,您已使用子模块添加了另一个名为“两个”的存储库。您需要注意的事项:
当您在“ two”中更改某些内容时,需要在“ two”中提交并推送,如果您位于顶级目录(即“ one”中),则您的更改将不会突出显示。
当未知用户尝试克隆您的“一个”存储库时,克隆“一个”后,该用户需要更新子模块以获取“两个”存储库
这些是一些要点,为了更好地理解,我建议您观看以下视频:https : //www.youtube.com/watch?v=UQvXst5I41I
为了克服这些问题,发明了子树方法。要了解有关git-subtree的基础知识,请查看以下内容:https : //www.youtube.com/watch?v=t3Qhon7burE
与子模块相比,我发现子树方法更可靠,更实用:)(我是很多初学者,可以说这些话)
干杯!
为了增加上述答案,与子模块相比,使用子树的另一个缺点是存储库大小。
我没有任何现实指标,但是考虑到每次在模块上进行一次推送,使用该模块的任何地方都会在父模块上获得相同更改的副本(随后在这些存储库上进行更新)。
因此,如果代码库被高度模块化,那么这将很快增加。
但是,鉴于存储价格始终在下降,这可能不是一个重要因素。
git gc
ZFS dedup(对象包)方面具有明显的不公平优势。因此,AFAICS较小的代码库(明智的是存储库大小而不是明智的存储库计数)应与子模块一起使用,较大的代码库应与monorepo一起使用。我还没有发现子树有任何用途。