在git存储库中的单个或多个项目之间进行选择?


223

git我们已将大多数项目模块化的环境中,我们面临着每个存储库一个项目每个存储库设计问题多个项目的问题。让我们考虑一个模块化项目:

myProject/
   +-- gui
   +-- core
   +-- api
   +-- implA
   +-- implB

今天,每个存储库一个项目。它给了自由

  • release 个别组件
  • tag 个别组件

但这对于branch组件也很麻烦,因为分支通常api需要和中的等效分支core,并且可能还有其他组件。

鉴于我们希望使用release单个组件,我们仍然可以通过每个存储库设计利用多个项目来获得类似的灵活性。

有哪些经验?您如何/为什么解决这些问题?


1
我现在有一个非常相似的问题。我需要发布项目的不同版本,因此它们将需要位于不同的存储库中。不过,这是一场噩梦。如果有一种仅分支子目录的方法,那就太好了。
Andrew T Finnell,2012年

1
每个模块需要有单独的版本号。我们使用git-describe
linquize 2013年



我很惊讶地看到没有提到Bit(bitsrc.io)和Lerna(github.com/lerna/lerna)!您可以在此处了解更多信息:hackernoon.com/…–
Yoni,

Answers:


199

one project per repository,您上面所描述的方式有三个主要缺点。如果它们确实是截然不同的项目,那么它们就不那么正确了,但是从它的声音来看,更改为一个项目通常需要更改为另一个项目,这确实会夸大这些问题:

  1. 何时发现错误很难发现。git bisect当您将存储库分解为子存储库时,诸如此类的工具变得更加难以使用。有可能,这不是那么容易,这意味着在危机时期寻找错误会变得更加困难。
  2. 跟踪功能的整个历史要困难得多。历史记录遍历命令就像git log在破碎的存储库结构中不像有意义地输出历史记录一样。您可以通过子模块或子树或通过其他可编写脚本的方法获得一些有用的输出,但这与键入tig --grep=<caseID>git log --grep=<caseID>扫描所有您关心的提交并不相同。您的历史记录变得更加难以理解,因此在您真正需要它时就没有用处了。
  3. 新开发人员需要花更多的时间来学习版本控制的结构,然后才能开始编码。每个新工作都需要选择程序,但是分解项目存储库意味着他们必须选择代码结构之外的VC结构。以我的经验,这对于刚接触git的开发人员来说尤其困难,这些开发人员来自使用单个存储库的更传统的集中式商店。

最后,这是机会成本的计算。在一位前雇主那里,我们将主要申请分为35个不同的子存储库。在它们之上,我们使用了一组复杂的脚本来搜索历史记录,确保状态(即生产分支与开发分支)在它们之间是相同的,并分别或批量部署它们。

太过分了。至少对我们来说太多了。管理开销使我们的功能变得不那么灵活,使部署更加困难,使新开发人员的教学花费了太多时间,到最后,我们几乎不记得为什么我们首先破坏了存储库。一个美丽的春天,我花了10美元在EC2中花了一个下午的集群计算时间。我回拨了仓库,打了几个git filter-branch电话。我们再也没有回头。


7
除了主题之外,作为存储库管理器,没有什么比在系统上花费更多时间才能愉快的事情了,该系统可以在两个小时内完成您的笔记本电脑在20小时内无法完成的工作,而且价格还不到午餐的价格。有时我真的很喜欢互联网。
克里斯托弗·

2
您如何将这些单独的项目作为单独的版本发布?还是您不需要这样做?那是我的问题。如果需要创建项目A的V1和项目B的V2,请使用
Andrew T Finnell 2012年

5
对于在“每个回购一个项目”和“多个回购”之间移动,请考虑使用git-subtree(在stackoverflow.com/a/17864475/15585上有很好的解释)
阻挠2013年

1
我编写了一个脚本来自动完成常见用例:github.com/Oakleon/git-join-repos
chrishiestand 2015年

什么是“ VC结构”?
罗伯特·哈维

60

Christopher在列举每个存储库一个项目的模型的缺点方面做得很好。我想讨论您考虑采用多存储库方法的一些原因。在我工作过的许多环境中,采用多存储库方法是一种合理的解决方案,但是要决定要拥有多少存储库以及在何处进行削减并不是一件容易的事。

在目前的职位上,我将拥有十多年历史的庞然大物单一存储库CVS存储库迁移到了许多git存储库中。自从最初的决定以来,存储库的数量已经增加(通过其他团队的行动),以至于我怀疑我们的存储量已经超过了最佳状态。一些新员工建议合并存储库,但我对此表示反对。Wayland项目也有类似的经验。在最近的一次演讲中,我看到他们曾经有200多个git存储库,而领导对此表示了歉意。查看他们的网站,我现在看到他们是5岁,这似乎很合理。请务必注意,加入和拆分存储库是一项可管理的任务,并且可以进行实验(在合理的范围内)。

那么什么时候需要多个存储库?

  1. 单个存储库太大而无法高效运行。
  2. 您的存储库松散耦合或分离。
  3. 开发人员通常只需要一个或一小部分存储库即可进行开发。
  4. 您通常希望独立开发存储库,并且只需要偶尔进行同步即可。
  5. 您想鼓励更多的模块化。
  6. 不同的团队在不同的存储库上工作。

如果第1点成立,则第2点和第3点才有意义。通过拆分存储库,我显着减少了异地同事的延迟,减少了磁盘消耗并改善了网络流量。

4和5更微妙。当您将客户端和服务器的存储库分开时,这使得协调客户端和服务器代码之间的更改的成本更高。这可能是积极的,因为这鼓励了两者之间的分离接口。

即使存在多存储库项目的不利影响,也还是要进行许多可观的工作-想到Wayland和Boost。我认为尚未就最佳做法达成共识,需要做出一些判断。用于多个存储库(git-subtree,git-submodule等)的工具仍在开发和试验中。我的建议是尝试并务实。


7
参考支持该主张的参考,该答案将更加有用:“加入和拆分存储库是一项可管理的任务。”
2015年

3
多个存储库也可以对抗模块化,因为它们使更改共享代码变得更加困难。跨仓库依赖关系使集成更加困难,可以更轻松地破坏代码(即使您有很好的工具来检查它),破坏仓库外代码的威胁会阻碍重构接口,这是您做事最强大的工具之一更加模块化。
Curt J. Sampson

关于MicroServices和DDD设计的所有内容都保存在这里。您应该最小化共享代码。
阿文

49

当我们使用GitHub时,实际上在一个存储库中有多个项目,但要确保这些项目/模块已正确模块化(我们使用-api和-core约定+ Maven +静态和运行时检查,甚至有可能一天到OSGi进行引导) 。

它节省了什么?好吧,如果我们要在多个项目中进行较小的更改,则不必发出多个“拉取请求”。问题和Wiki保持集中化等。

我们仍然将每个模块/项目视为一个适当的独立项目,并在CI服务器等中分别构建和集成它们。


1
很有意思。我怀疑这是github上的常见模型。如果您面对单独的组件发行版,您是否使用类似的东西submodules或发布/标记整个存储库?
JohanSjöberg2012年

子模块(如果需要的话),但现在我们从父版本开始进行版本控制。
Martijn Verburg 2012年

在我目前的雇主处,我们使用类似的策略,并将有关项目中最新提交的元数据打包到工件的各种清单文件中(即的结果git log -1 -- <project_dir>)。真的很棒。这个答案值得更多的赞扬。
Christopher

22

对我而言,使用一个或多个存储库的主要区别在于以下问题的答案:

  • 同一团队开发的多个零件是否具有相同的发布周期,相同的客户?然后,很少有理由拆分一个存储库。
  • 多个部分是否高度相互依赖?因此,由于彼此之间的高度依赖,因此拆分模型,控制器和UI(即使它们是不同的部分)也不是很明智。但是,如果2个部分仅具有较小的依赖性,这是通过一个仅每隔几年更改一次的稳定接口来实现的,那么将2个部分划分为2个存储库是明智的。

举例来说,我有一个小型应用程序(仅客户端),用于检查Subversion存储库的“质量”。有一个核心实现,可以从命令行启动,并且可以与Java 6很好地兼容。但是我已经开始实现一个UI,该UI使用JavaFX作为Java 8的一部分。因此,我将2拆分为一个,第二个存储库(具有第二个构建过程),具有不同的时间表,...

我喜欢上面的答案(投票赞成),但我认为它们并不是全部真实的故事。因此,我也想添加用于拆分存储库的参数。因此,真正的答案(何时拆分)可能在中间的某处...



0

根据您的示例,应该根据存储库之间的相互依赖性来设置存储库。设计MicroService和域驱动设计的所有理由都适用于此:在某些情况下,重复的代码是可以接受的,可以使用接口,除非确实需要,否则不要破坏兼容性,等等。

现在在我看来,UI应该独立于后端。因此,UI项目存储库通常应包含UI代码和客户端控制器。客户端控制器将以抽象方式与服务控制器连接。他们将使用与服务分开版本的服务客户端/ api抽象,以便可以在不中断客户端的情况下更新服务(可能有多个不同的客户端)。

因此,服务本身应该是其自己的存储库。在我看来,该服务只是某些单点业务逻辑的包装。因此,业务逻辑通常应与托管它的服务技术分开。另一方面,存储库实现通常紧密地连接到业务逻辑,以至于可以将其集成在同一存储库中。但即使在那儿,您的行驶里程也可能会有所不同。

当然,在技术或支持多个堆栈方面变化不大的简单项目中,所有UI都可以从与后端相同的源托管,而后端服务通常仅由同一客户端使用,因此可以从更多项目中受益。紧密集成的存储库。

在这种情况下,将完整的垂直存储在一个存储库中可能会很好,并且专注于确保功能域在其自己的存储库中正确独立。这样,您仍然具有较小的存储库的最大优点,而其他方面的开销却很小。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.