在git中,如何对十二个库进行版本控制


11

我们正在做项目,但是我们在项目之间重用了很多代码,并且有很多包含我们共同代码的库。在实施新项目时,我们发现了更多方法来分解通用代码并将其放入库中。这些库相互依赖,而项目则取决于这些库。每个项目以及该项目中使用的所有库都需要使用它们所引用的所有库的相同版本。如果我们发布某个软件,则我们将不得不修复错误,并可能添加许多年甚至数十年的新功能。我们有大约十二个库,更改通常跨越两个以上,并且几个团队并行处理多个项目,并同时对所有这些库进行更改。

我们最近已切换到git并为每个库和每个项目设置存储库。我们使用存储作为公共存储库,在功能分支上进行新工作,然后发出拉取请求并仅在审阅后合并它们。

我们必须在项目中处理的许多问题都要求我们在多个库和项目的特定代码之间进行更改。这些通常包括库接口的更改,其中一些不兼容。(如果您认为这听起来有些可疑:我们与硬件进行交互,并将特定的硬件隐藏在通用接口之后。几乎每次我们集成其他供应商的硬件时,都会遇到我们当前的接口无法预期的情况,因此必须对其进行完善。)例如,假设一个项目P1使用的库L1L2L3L1还采用了L2L3,并L2使用L3为好。依赖关系图如下所示:

   <-------L1<--+
P1 <----+  ^    |
   <-+  |  |    |
     |  +--L2   |
     |     ^    |
     |     |    |
     +-----L3---+

现在,想象一下此项目的功能需要更改,P1L3更改的界面L3。现在添加项目P2并添加P3到组合中,它们也引用这些库。我们不能将它们全部切换到新界面,运行所有测试并部署新软件。那有什么选择呢?

  1. 在中实现新接口 L3
  2. 提出请求L3并等待审查
  3. 合并变更
  4. 创建一个新版本 L3
  5. P1通过参考L3的新版本开始使用该功能,然后在其P1功能分支上实现该功能
  6. 提出拉取请求,对此进行审核并合并

(我只注意到我忘了切换L1,并L2到新版本,而我甚至不知道在哪里要坚持这一点,因为这将需要同时做同P1...)

这是一个繁琐,容易出错的过程,并且实施此功能的过程非常漫长,它需要进行独立审核(这使得审核变得更加困难),根本无法扩展,并且有可能使我们停业在过程中陷入困境,我们永远都做不完。

但是,如何使用分支和标记来创建一个流程,使我们能够在新项目中实现新功能而又没有太多开销?


1
更改工具不应过多地影响现有的流程。那么,在切换到git之前,您如何处理这个问题?
Bart van Ingen Schenau 2015年

当太多的库依赖于该接口时,是否可以在不破坏现有接口的情况下简单地向该接口添加新方法?通常,这不是最好的主意,但至少可以让您“继续”实现新功能,并且只要有空就可以适当弃用旧方法。还是这些接口对于这样的“并行接口”来说太有状态了?
Ixrec 2015年

1
@Ixrec:有人告诉我,这不是做事的git方法。每个人都为单个项目使用单独的存储库,因此我们也决定这样做。
2015年

2
我会辩称,如果经常必须一并更改它们,它们就不是独立的项目。“项目”之间的边界应始终具有某种长期的向后兼容性保证imo。
Ixrec 2015年

1
@Ixrec:集成更多的硬件类似于将代码移植到更多的平台上:您做得越多,就无需为另一个硬件/平台进行更改。因此,从长远来看,代码将稳定下来。但是,现在我们需要找到一种流程,使我们能够在市场上停留足够长的时间才能到达那里。
sbi 2015年

Answers:


5

有点在这里说清楚,但也许值得一提。

通常,git repos是针对每个库/项目量身定制的,因为它们往往是独立的。您可以更新项目,而不必关心其余的事情。取决于它的其他项目将在他们认为合适的情况下简单地更新其lib。

但是,您的案例似乎高度依赖于相关组件,因此一项功能通常会影响其中的许多组件。整个必须打包成捆。由于实现功能/更改/错误通常需要一次适应许多不同的库/项目,因此将它们全部放在同一个存储库中可能是有意义的。

有很强的优势/缺点。

优点:

  • 可跟踪性:该分支显示了每个项目/库中与此功能/错误相关的所有更改。
  • 捆绑:只需选择一个标签,即可正确使用所有来源。

缺点:

  • 合并:...单个项目有时已经很困难。由不同的团队在共享分支机构中工作,请做好准备以备影响。
  • 危险的“哎呀”因素:如果一名员工因犯了一些错误而弄乱了存储库,则可能会影响所有项目和团队。

由您决定价格是否值得。

编辑:

它将像这样工作:

  • 功能X必须实现
  • 创建分支 feature_x
  • 所有涉及此分支的开发人员都可以在该分支上并行工作,可能在与他们的项目/ lib相关的专用目录中
  • 一旦结束,请进行检查,测试,包装,无论如何
  • 将其合并回主服务器中……这可能是困难的部分,因为与此同时feature_y,它feature_z可能也已添加。它成为“跨团队”合并。这就是为什么它是一个严重的缺点。

仅作记录:我认为在大多数情况下这是一个坏主意,应谨慎进行,因为合并缺陷通常比通过依赖项管理/适当的功能跟踪获得的缺陷要高。


谢谢,我们确实正在研究这个。鉴于此,我不明白的是我们将如何使用git进行分支。在SVN中,分支意味着将子树(在存储库中)复制到其他地方(在存储库中)。这样,很容易在仓库中创建任何子树的分支,因此,如果其中有很多项目,则可以分别分支每个子树。git中是否有类似的东西,还是我们总是只能分支整个仓库?
2015年

@sbi:您会分支整个仓库。您不能使用不同分支中的子树,这在您的情况下有点不足。Git不会“复制”任何东西,它只会跟踪您正在处理的分支中的更改。
dagnelies

因此,这需要某人为一个库创建功能分支,以便在合并或重新建立基础时也合并所有其他库。这是一个真正的缺点。(顺便说一句,SVN也只做过惰性复制。)
sbi 2015年

@sbi:请参见编辑
dagnelies

1
好吧,目前我们大多数人都不舒服。:-/而且,即使是那些(并推动使用git的人)也不知道如何使我们的开发过程适合git。叹。恐怕要等几个月以后,情况才能变得更加顺利。无论如何,谢谢您是迄今为止最有帮助的答案。
sbi 2015年

4

您正在寻找的解决方案是与git子模块配合使用的依赖项管理工具

工具如:

  • 马文
  • 蚂蚁
  • 作曲家

您可以使用那些工具来定义项目的依赖关系。

您可以要求子模块的版本至少为> 2.xx,或者表示一系列兼容的版本= 2.2。*或小于特定版本<2.2.3。

每当您发布其中一个软件包的新版本时,都可以使用版本号对其进行标记,这样就可以将特定版本的代码引入所有其他项目中。


但是依赖管理不是我们的问题,这可以解决。目前,我们经常在许多库中进行更改,并且需要在保持稳定的项目版本的同时最大程度地减少创建新版本的开销。您的答案似乎并未提供解决方案。
6

@sbi这将管理创建新版本和维护稳定项目版本的开销。由于您可以确定项目x依赖项目y版本2.1.1,因此可以创建不会影响项目x的项目y新版本。
Patrick

同样,声明依赖关系不是我们的问题。我们已经可以做到这一点。问题是如何有效地管理跨多个项目/库的变更。您的答案无法解释这一点。
sbi 2015年

@sbi:那到底是什么问题?您进行更改,更改版本,在需要时更新依赖项,然后瞧。您在最初的帖子中描述的是典型的maven&co。东西。每个发行版均基于明确定义的版本库。怎么会更清楚?
dagnelies 2015年

@arnaud:这种(目前相当普遍的)变更过程跨越三层或更多层的周转时间将使我们丧命。我以为我的问题描述了这一点。
sbi 2015年

0

子模块

您应该尝试在一个注释中建议git子模块

当项目P1是指三个子模块L1L2并且L3,它实际存储在所有三个仓库,以特定的提交参考:这些都是工作的每个库的版本该项目

因此,多个项目可以与多个子模块一起工作:当项目使用新版本时,P1可能引用旧版本的库。L1P2

交付新版本的会发生什么L3

  • 在中实现新接口 L3
  • 提交,测试,发出拉取请求,查看,合并...(您无法避免)
  • 确保L2L3,提交,...一起工作
  • 确保L1与新的L2...一起使用
  • 确保P1适用于所有库的新版本:
    • 里面P1的本地工作副本L1L2并且L3,fetche你有兴趣的变化。
    • 提交更改,git add L1 L2 L3以提交对模块的新引用
    • 提取请求P1,测试,审查,提取请求,合并...

方法

这是一个繁琐,容易出错的过程,并且实施此功能的过程非常漫长,它需要进行独立审核(这使得审核变得更加困难),根本无法扩展,并且有可能使我们停业在过程中陷入困境,我们永远都做不完。

是的,它需要独立审核,因为您需要更改:

  • 图书馆
  • 依赖它的库
  • 依赖多个库的项目

你会因为丢人而倒闭吗?(实际上可能不是)。如果是,那么您需要执行测试并检查更改。

使用适当的git工具(甚至gitk),您可以轻松查看每个项目使用的库版本,并可以根据需要独立更新它们。子模块非常适合您的情况,并且不会减慢您的处理速度。

也许您可以找到一种自动执行此过程的一部分的方法,但是上述大多数步骤都需要人脑。缩短时间的最有效方法是确保您的库和项目易于开发。如果您的代码库可以很好地处理新要求,那么代码审查将变得更加简单,并且只需很少的时间。

(编辑) 可能对您有所帮助的另一件事是将相关的代码审阅分组。您提交所有更改,并等到将这些更改传播到使用它们的所有库和项目之后,再对拉取请求进行汇总(或处理它们)。您最终需要对整个依赖项链进行更大的审查。如果每个本地更改很小,这也许可以帮助您节省时间。


您将描述如何解决依赖关系问题(正如我之前所说的,我们已经解决了这个问题)并消除了我们所遇到的问题。你为什么还要打扰?(FWIW,我们编写的驱动发电厂的软件。干净,安全且经过全面审查的代码是主要功能。)
2015年

@sbi如果不是分支和标记的特殊情况,什么是子模块?您认为子模块与依赖性管理有关,因为子模块还跟踪依赖性。但是可以肯定的是,如果您愿意,请使用标签重新创建子模块,我不在乎。我不明白您的问题:如果经过审查的代码是主要功能,则您必须花一些时间进行审查。您不会陷入困境,您会受到约束的影响而尽可能快地前进。
coredump

评论对我们非常重要。这就是我们关注某个问题(及其评论)的原因之一,该问题因多个存储库中的多个更改而被分为多个评论。另外,我们不想因为一个问题而陷入僵局,因为我们宁愿花时间编写和审查代码。重新子模块:到目前为止,我所听到的关于它们的唯一一件事就是“不要打扰,这不是git方法”。好吧,鉴于我们的要求似乎是如此独特,也许我们应该重新考虑这个决定……
sbi 2015年

0

所以我了解的是,对于P1,您想更改L3接口,但是您希望其他依赖L3接口的P2和P3立即更改。这是向后兼容的典型情况。关于保留向后兼容性,有一篇不错的文章

有几种方法可以解决此问题:

  • 您每次都必须创建新接口,以扩展旧接口。

要么

  • 如果要在一段时间后停用旧界面,则可以使用多种版本的界面,并且一旦所有相关项目移动后,您将删除旧界面。

1
不,可以通过发布分支来确保向后兼容,这不是我们的问题。问题是我们坐在一个当前快速变化的代码库上,尽管接口仍然处于经常更改的阶段,但现在我想将其分离为库。我知道如何在SVN中管理此类野兽,但不知道如何在git中做到这一点而不会被管理所淹没。
2015年

0

如果我正确解决了您的问题:

  • 您有4个相互关联的模块,P1和L1至L3
  • 您需要对P1进行更改,这最终会影响L1至L3
  • 如果必须同时更改所有四个,则视为过程失败
  • 如果必须将它们全部更改为1,则视为过程失败。
  • 如果您必须提前确定必须进行更改的块,则将其视为过程失败。

因此,目标是您可以一次完成P1和L1,然后一个月后再进行一次L2和L3。

在Java世界中,这很简单,也许是默认的工作方式:

  • 一切都在一个存储库中进行,没有分支的相关使用
  • 模块根据版本号由maven编译+链接在一起,而不是全部都在同一目录树中。

因此,您可以将L3本地代码存储在本地磁盘上,如果该代码是针对磁盘上其他目录中的P1副本进行编译的,则该代码不会编译;幸运的是它没有这样做。Java可以直接执行此操作,因为编译/链接故事是针对已编译的jar文件而不是源代码。

对于C / C ++世界,我不知道针对此问题已存在的广泛使用的解决方案,并且我想您几乎不想切换语言。但是很容易将与做同样事情的make文件一起黑客入侵:

  • 已安装的库+带有已知版本号的已知目录的头
  • 更改了每个模块到目录的相应版本号的编译器路径

您甚至可以在maven中使用C / C ++支持,尽管如果您这样做,大多数C开发人员都会奇怪地看着您...


“如果必须一起更改全部4个,则视为过程失败”。其实不会。实际上,这正是我们使用SVN所做的。
sbi

那么在那种情况下,我想将所有项目简单地放入存储库中就没有问题。
soru

我们现在正在评估将库仅放入两个存储库中。这还不止一个,但是比“每个项目一个”要少得多,而且库可以很好地分为两组。感谢您的输入!
履行机构

PS:“我想您几乎不想切换语言。” 这是嵌入式的东西。:)
履行机构

-1

有一个简单的解决方案:在整个存储库中剪切发行版分支,将所有修补程序合并到所有活跃发布的发行版中(很明显,很容易在git中实现)。

随着时间的推移,随着项目的发展,所有替代方案都会造成可怕的混乱。


您能详细说明一下吗?我不确定您的建议。
sbi 2015年

在明确的情况下,您将分支点定义为基础分支和时间戳。您具有以下层次结构:基本分支->发布-开发-分支->私有开发分支。所有开发都在私有分支上完成,然后合并到层次结构中。客户发布分支已脱离发布-开发分支。我对git不太熟悉,但在自由源代码控制系统中,这似乎是最清楚的案例。
zzz777

仔细阅读我的问题应该会告诉您,我们在传播存储库之间的更改所涉及的开销方面存在问题。这与您的答案无关。
6

@sbi对不起,我误解了您的问题。恐怕您迟早会遇到可怕的混乱。
zzz777 2015年
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.