何时将大型Git仓库分成较小的仓库?

18
我正在进行从 SVN 到 Git 的迁移。我已经使用了 git-svn 将历史记录放入单个的 Git 存储库中,我已经知道如何使用 git-subtree 将该存储库拆分成更小的存储库。这个问题不是关于如何执行迁移,而是关于何时拆分和何时不拆分。
我想拆分大型存储库,因为其中一些目录是独立的库,也与其他项目共享。以前,可以在不需要检出整个项目的情况下对库进行svn checkout操作。在所有这些过程中,我发现可能有几十个目录是有意义的,因为它们是1)独立的并且2)跨项目共享的。
当你超过几个 Git 存储库时,使用一个能够更轻松地管理多个存储库的工具似乎很明智。一些例子包括 Google 的repogit submodulesgit subtree和创建自定义脚本(似乎 Chromium 这样做)。我已经探索了这些不同的方法,并知道如何使用它们。
因此,问题是关于从 SVN 转换的方向。 我应该尽量坚持使用一个大的 Git 存储库,只有在绝对必要时才将其拆分成更小的部分,还是应该将其拆分成数十甚至数百个更小的存储库?哪种方法更容易使用?是否有其他的解决方案?如果选择使用多个存储库,应该使用哪个工具?什么因素会使人偏爱一种方法而不是另一种方法?
注意:源代码需要在 Windows、MacOS 和 Linux 上检出。

1
“如何确定是否应该分割 Git 存储库?”也许这是我提出问题的更好方式? - onionjake
为什么需要使用脚本来控制子树?你是在谈论使用钩子自动同步它们之间的项目吗?因为我经常使用子树,而且有意不希望它们自动同步。通常情况下,需要使用其中一个库的超级项目很长时间都没有被修改,当我返回该项目时,发现它仍然正常工作是很好的。如果以后我继续处理这个项目,我可能会手动决定拉取库更改,并处理超级项目中的任何破坏性更改。 - johnb003
@johnb003 很多库正在积极开发中,需要频繁更新。 - onionjake
请参考以下链接:http://programmers.stackexchange.com/questions/161293/choosing-between-single-or-multiple-projects-in-a-git-repository - onionjake
5个回答

6
那个过程可以通过组件化方法进行引导,其中你需要确定一组连贯的文件(应用程序、项目、库)。
在历史方面(在源代码控制工具中),一个连贯的集合意味着它将被标记、分支或合并为一个整体,而独立于其他文件集合。
对于分布式版本控制系统(如git),每个这些文件集合都是其自己的git存储库的好选择,然后您可以使用子模块将那些您需要用于特定项目的文件组合在父存储库中。
例如,我在以下文章中描述了这种方法:
- "Git repository setup for a project that has a server and client"(服务器和客户端是两个明显的连贯分离的集合,受益于拥有自己的存储库) - "What is Component-Driven Development?"

相反的做法(将所有内容放在一个仓库中)被称为“基于系统的方法”,但可能会导致Git仓库变得非常庞大,正如我在“Git性能”中提到的那样,这与Git的实现方式不兼容。


OP onionjake评论区中问道:

您能否提供更多有关识别组件细节的信息?

识别“组件”(这些组件最终成为git仓库)的过程是由系统的软件架构指导的。
任何作为独立文件集合的子集都是自己仓库的好选择。它可以是库或dll,也可以是应用程序的一部分(GUI、客户端与服务器、调度程序等)。

每当您识别到一组紧密链接的文件(意味着修改一个文件可能会影响其他文件),它们应该是同一个组件的一部分,或者在git中,是同一个仓库。


这个回答很出色,让我想要了解更多。您能否请提供更多关于鉴别元件细微差别的信息呢?或许可以举一个详细的例子来说明吗? - onionjake

3

个人而言,我喜欢小型仓库 - 当你有像PHP的Composer这样的良好依赖管理系统时,它们可以很好地发挥作用。

它消除了管理检出过程的痛苦,还可以跟踪版本等。

它还允许不同提供商托管仓库。我们使用定制代码和开源仓库的组合。


+1 提到了Composer,它似乎恰好解决了这个问题。它能在非PHP项目中使用吗? - onionjake
这是一个 PHP 的解决方案,但其他编程语言也有替代方案,例如,Java 可以使用 Maven。 - BillyBigPotatoes
对于Python,有setuptools。然而,一般来说,这些工具与用于拆分项目的标准关系不大。 - johnb003

2

我建议大部分或者全部情况下都使用子树,如果你认为必要,可以自由地创建子树。

当依赖项很多时,子模块会变得非常麻烦。如果你对这些依赖项的开发有影响,那么情况就更加复杂了。如果你有一个完全的第三方库,不经常更改版本,并且你永远不会作为整个项目的一部分积极地进行开发,则子模块可能是可行的。

对于实际工作中的依赖项来说,子模块与超级仓库相隔太远。

例如:如果你对子模块进行更改,则必须在子模块上提交,推送,切换到超级仓库,将子模块添加到索引/阶段,提交并再次推送。这是一个麻烦的工作流程。更不用提删除、移动或重命名子模块的麻烦了。

Git子树更好。历史记录交织在一起,但是你可以随意将目录拆分为子树。如果你决定不再将某个目录视为子树...只需停止执行子树拆分或推送即可。

子树的缺点是它们根本没有被跟踪。因此,你必须记住所有路径及其与其存储库的关系 - 任何其他在项目上工作的人也只需知道他们想要执行子树操作即可。好消息是,大多数开发人员可以在不担心如何将代码推出到这些存储库的情况下,在任何依赖项上工作。另外,正如你所说,一些bash脚本可以帮助自动化手动操作。


我同意你对子树和子模块的评估,但这并没有真正回答这里提出的问题。话虽如此,你提到的关于子树的缺点,我认为可以通过一个贡献来轻松解决,使它们写入.git/config。我也在TortoiseGit中直接解决了一些问题。 - johnb003
我认为它回答了问题,或者至少对此有所帮助。我的意思是,使用子树时,这并不那么重要。你可以先不创建子树,稍后再将目录转换为子树 - 随心所欲。你现在可以创建一堆子树,如果以后不需要它们,就可以忘记它们。我想说的是,子树让你不必过于担心从一开始就做出正确的决定。 - eddiemoya
是的,我认为子树的缺点将很快被解决。已经有一些脚本可以解决这个问题了。 - eddiemoya
哦,那样的话我完全同意,基本上就是我给出的相同答案 :P +1 - johnb003

1
当您有一个适用于多个项目的良好重用案例时,请考虑将其拆分为子项目。在使用它的两个项目之前,我会避免创建共享项目。
我考虑使用以下标准来考虑制作子项目存储库:
1. 是否被多个项目使用? 2. 是否是自包含的? 3. 是否经常更改?
我发现子树最易于管理,因为我可以将库作为项目的一部分开发,然后在需要时拆分它。
我还想指出,两个项目在公共库上分歧是完全可以接受的,通常更喜欢这样做以保持它们处于稳定状态。只要容易合并公共代码,我认为采取懒惰的方法共享库是没有害处的。
无论如何,这是一个好迹象;这意味着您已经成功地创建了可重复使用的代码。 :)

1
当你在分布式环境中工作时,考虑到git的功能,如果那些组件被其他项目使用或者如果将来可能或者希望发生这种情况,你应该避免直接将不同的组件直接分组到单个仓库中。这是因为开发人员/贡献者可以专注于自己的部分,而无需下载他们不打算使用/更改的每个其他组件的完整历史记录。如果您与互联网速度比我们习惯的慢的国家/地区的贡献者一起工作,这也非常重要。
由于您尝试并了解了各种方法,因此您不会被困在低知识水平,并且这不应该是一个艰巨的任务。据我所知,您拥有所有可能的替代方案。
如果它们与主存储库相互独立,我不会担心拥有数十个甚至数百个较小的存储库。如果您需要迁移“立即”从子版本控制,则应支持大型存储库解决方案。或者是对替代方案没有或者只有低级知识的人员。
我建议使用 git subtree ,因为它是与git一起作为标准功能提供的:用户不需要安装任何额外的东西,只需使用git即可,并且它会一直保留,直到git不再支持为止。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接