什么时候使用git subtree?

2cmtqfgy  于 8个月前  发布在  Git
关注(0)|答案(6)|浏览(95)

git subtree解决了什么问题?何时以及为什么应该使用该功能?
我读到它是used for repository separation,但是为什么我不创建两个独立的仓库,而不是把两个不相关的仓库放在一个仓库里呢?
这个GitHub教程解释了how to perform Git subtree merges
我知道如何使用它,但不知道何时使用它(用例)和为什么使用它,以及它与git submodule的关系。

7d7tgy0s

7d7tgy0s1#

当你在git的上下文中使用术语"子树“**时,你应该小心地明确指出你在谈论什么,因为这里实际上有两个独立但相关的主题:
git-subtreegit subtree merge strategy

TL;DR

.gitmodules不同的是,git-submodule只将元数据存储在根存储库中,并且必须单独管理外部存储库。

更多详情

git subtree merge strategy基本上是使用你引用的命令的更手动的方法。
git-subtree是一个 Package 器shell脚本,以促进更自然的语法。这实际上仍然是contrib的一部分,并没有完全集成到git中。documentation存储在脚本的沿着。

以下是使用信息:

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>]

字符串
我已经遇到了相当多的关于子树主题的资源,因为我打算写一篇自己的博客文章。如果我这样做,我会更新这篇文章,但现在这里有一些与手头问题相关的信息:
您正在寻找的大部分内容可以在Nicola Paoluccithis Atlassian blog上找到,相关部分如下:

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

您可能会发现subtree更适合用途:

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

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

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

我也同意这一点,我建议你看看这篇文章,因为它涉及到一些常见的用法。
您可能已经注意到,他还写了一个后续的here,其中他提到了一个重要的细节,这是与这种方法离开.
git-subtree当前无法包含远程!
这种短视可能是由于人们在处理子树时经常手动添加一个remote,但这也没有存储在git中。作者详细介绍了他编写的一个补丁,用于将此Meta数据添加到git-subtree已经生成的提交中。在此补丁成为官方git主线之前,您可以通过修改提交消息或将其存储在另一个提交中来做类似的事情。
我也发现this blog post非常有用。作者添加了第三个子树方法,他称之为git-stree。这篇文章值得一读,因为他很好地比较了这三种方法。他给出了他个人的观点,他做了什么,不喜欢什么,并解释了为什么他创建了第三种方法。

其他

结束语

本主题展示了git的强大功能,以及当要素刚好错过标记时可能发生的分割。
我个人对git-submodule很反感,因为我发现它对贡献者来说更容易理解。我也更喜欢在我的项目中管理所有依赖项,以促进易于复制的环境,而无需尝试管理多个存储库。git-submodule,然而,目前它更为人所知,因此了解它显然是件好事,并取决于可能影响您决定的受众。

67up9zun

67up9zun2#

首先:我相信你的问题往往会得到强烈的固执己见的答案,可能会被认为是偏离主题在这里。但是,我不喜欢这样的政策,并会推动边界的主题有点向外,所以我喜欢回答,而不是希望别人也这样做。
在你提到的GitHub教程中,有一个指向How to use the subtree merge strategy的链接,它给出了关于优点/缺点的观点:
比较子树合并与子模块
使用子树合并的好处是对仓库用户的管理负担更少。它适用于旧版(Git v1.5.2之前)客户端,并且克隆后您就可以获得代码。
但是如果你使用子模块,那么你可以选择不传输子模块对象。这可能是子树合并的问题。
此外,如果您对其他项目进行更改,如果您只使用子模块,则提交更改会更容易。
以下是我基于上述的观点:
我经常和人们一起工作(=committers)不是常规的git用户,有些仍然是(并且将永远)与版本控制作斗争。教育他们如何使用子模块合并策略基本上是不可能的。它涉及到额外远程的概念,关于合并,分支,然后将其混合到一个工作流中。从上游拉取和向上游推送是一个两阶段的过程。由于分支对他们来说很难理解,这一切都毫无希望
对于子模块来说,它仍然太复杂了(* 叹息 *),但它更容易理解:它只是一个repo中的repo(他们熟悉层次结构),你可以像往常一样做你的推拉。
提供简单的 Package 器脚本对于子模块工作流来说更容易。
对于包含许多子存储库的大型超级存储库,选择不克隆某些子存储库的数据是子模块的一个重要优势。我们可以根据工作需求和磁盘空间使用情况限制这一点。
访问控制可能会有所不同。还没有遇到过这个问题,但是如果不同的存储库需要不同的访问控制,有效地班宁一些用户访问一些子存储库,我想知道使用子模块方法是否更容易实现。
就我个人而言,我还没有决定用什么。所以我分享你的困惑:o]

9w11ddsr

9w11ddsr3#

基本上Git-subtree是Git-submodules方法的替代品:有很多缺点,或者更确切地说,你需要在使用git-submodules时非常小心。例如,当你有“一个”repo,而在“一个”里面,你已经使用子模块添加了另一个名为“两个”的repo。你需要注意的事情:

  • 当你在“two”中修改一些东西时,你需要在“two”中提交和推送,如果你在顶层目录(即在“one”中),你的修改不会被突出显示。
  • 当一个未知的用户试图克隆你的“一个”仓库时,在克隆“一个”之后,该用户需要更新子模块以获得“两个”仓库。

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

  • 为了克服这些问题,子树方法被发明出来。要了解git-subtree的基础知识,请查看以下内容:https://www.youtube.com/watch?v=t3Qhon7burE
  • 我发现子树方法比子模块更可靠和实用:)(我是一个初学者,可以说这些事情)

干杯!干杯!

tvz2xvvm

tvz2xvvm4#

我们有一个真实的用例,其中git subtree是一个救赎:
我们公司的主要产品是高度模块化的,在不同的仓库中的多个项目中开发。所有模块都有自己的路线图。整个产品由具体版本的所有模块组成。
在并行的整个产品的具体版本是定制为我们的每个客户-为每个模块单独的分支。定制有时必须在几个项目一次(cross-module customization)。
为了让定制产品有一个独立的产品生命周期(维护,功能分支),我们引入了git subtree。我们为所有定制模块提供了一个git subtree存储库。我们的定制是每天'git subtree push'回到所有原始存储库到定制分支。
这样我们就避免了管理许多仓库和分支。git-subtree使我们的生产力提高了好几倍!

更新

有关已发布到评论的解决方案的更多详细信息:
我们创建了一个全新的仓库。然后我们将每个拥有客户端分支的项目作为子树添加到新的仓库中。我们有一个jenkins任务,定期将原始仓库的主更改推回客户端分支。我们使用带有功能和维护分支的tillinggit flow来处理“客户端仓库”。
我们的“客户”仓库也有我们也为这个特定客户改编的构建脚本。
然而,提出的解决方案存在一个缺陷。
随着我们离产品的主要核心开发越来越远,特定客户端的可能升级越来越困难。在我们的情况下,由于子树之前的项目状态已经远离主路径,所以子树至少引入了顺序和可能性来引入默认的git流。

6yt4nkrj

6yt4nkrj5#

为了补充以上答案,使用子树的另一个缺点是与子模块相比的repo大小。
我没有任何真实的世界指标,但考虑到每次对模块进行推送时,使用该模块的任何地方都会在父模块上获得相同更改的副本(随后在这些repos上更新时)。
因此,如果一个代码库是高度模块化的,那么它将很快增加。
然而,考虑到存储价格总是在下降,这可能不是一个重要因素。

dba5bblo

dba5bblo6#

我不得不停止使用子模块,因为一个错误,你搞砸了你的回购为自己,和其他人,这是很难修复(“* 哎呀,哪个子模块提交与主代码匹配,我忘记在哪里签入了?* ”)。我得出的结论是,如果git只是默认总是检查整个代码库,包括任何子模块,也可以提交和推送整个代码库,包括子模块,* 除非特别告知不要这样做 *,子模块将非常容易使用。简单地默认将整个嵌套仓库集视为一个大的虚拟仓库(这是默认情况下应该是的,为什么你要包括一个子模块,如果它对项目不是必需的),除非你明确地需要做一些不同的事情,这可能是例外。优化大小,这是git目前所做的,在这个世界上,一个TB的磁盘空间花费$10和很多人有千兆互联网。

相关问题