在一个面向多个客户的Web项目中使用Git

15

有没有更好的提案来使用git版本控制带有小型随机更新的多个客户项目的Web项目?

我想使用git来进行Web项目的版本控制。与几乎所有其他建议的主要区别在于,这是一个使用HTML、JavaScript和一些PHP文件的Web项目-没有像典型Linux软件包中那样由一个或多个程序使用的中央库。

我所有不同的Web项目都是为不同的客户基于相同的平台文件,我估计80%的文件是相同的(称之为平台),20%被修改以适应不同客户的需求。问题在于,我不知道哪些文件需要进行客户更新-具体而言,每个客户都不同。

最好将特定于平台的文件保存在一个目录中,并在另一个目录中使用客户特定的文件覆盖这些文件。要使用git解决这个问题,到目前为止我还没有找到真正好的方法:

  • git子模块 (如此处所建议的) 通常设计用于使供应商开发的库的源文件接近链接它的程序。因此问题在于平台文件和客户文件位于不同的目录中,因此我必须在部署期间混合它们以创建Web服务器的文件。此外,我还必须手动同步目录树,对于10级目录结构来说,这将是非常繁琐的工作。总的来说,很多帖子都抱怨使用子模块需要大量管理工作,看起来有些过度了。
  • git子树 (如此处所建议的) 似乎比子模块简单,但存在与不同目录相同的问题,因此在部署期间我还需要保持目录结构同步并混合文件。此外,难以从客户端回推平台更改。
  • GitSlave (如此处所建议的)
  • 我不确定这对我是否有好处。它允许保持多个git仓库同步,也许有助于同步平台的目录结构,但我无法相信它。
  • 在不同目录中重构平台和客户文件(如讨论的结果) 我认为在我的客户和Web项目所使用的技术情况下,这是不可能的。对于一个客户,需要更新这个页面,另一个客户需要更新那个页面。即使引入了PHP框架,客户特定的更改也会分散在整个树中。
  • 检出(如同讨论中最后一篇帖子所提出的) 这看起来非常简单和有前途,但缺点是所有特定于客户的文件都不在git之内(因此不在版本控制之内)。此外,在平台和客户端更新文件的情况下,git pull会失败并终止,因此不可用。
  • 供应商分支(如此处推荐的) 据我所知,分支是用来合并回来的,这不是针对我的特定客户补丁的。这些分支将始终保持打开状态,仅在平台(主)向客户端更新后合并。这将导致一个包含所有客户和平台信息的巨型repo - 这不是git处理repo的方式。
  • 混合部署。因此,一种非常实用的方法是将平台文件保存在一个repo中,将客户文件保存在专用repo中。在部署文件到Web服务器时,可以首先写入所有平台文件,然后用平台特定文件覆盖其中一些。混合发生得很晚,在Web服务器目录中。这也有一个缺点,即每个客户的目录结构必须手动与平台结构保持同步 - 否则部署将过于复杂。

这里最好的方法是什么?


就此而言,感谢您至少花时间研究一些选项,而不是期望其他人为您完成所有工作。 - Roman
感谢sjas进行重新格式化和微调,现在阅读起来真的更好了! - Achim
嗨R0MANARMY,我在这个问题上已经花费了几周的时间。我最初期望在标准的git文档中找到解决方案(我也是git的新手),但意识到我的用例似乎与git的主要用例不同。 - Achim
2个回答

5

简述

这实际上是一个架构设计问题,而不是源代码管理问题。尽管如此,这是一个常见而有趣的问题,因此我提供了一些关于如何解决架构问题的一般建议。

并不是Git的问题

问题并不是Git。问题在于您没有充分区分哪些方面保持不变,哪些方面会随着客户而改变。一旦确定了正确的设计模式,适当的源控制模型将更加明显。

考虑一下Russ Olsen的这句话:

[将]可能发生变化的事物与可能保持不变的事物分开。如果您可以确定系统设计中哪些方面可能会发生变化,就可以将这些部分与更稳定的部分隔离开来。

Olsen, Russ (2007-12-10). Design Patterns in Ruby (Kindle Locations 586-588). Pearson Education (USA). Kindle Edition.

一些重构建议

我不太清楚您的应用程序,无法提供具体建议,但总的来说,Web项目可以从几种不同的设计模式中受益。模板、组合或原型模式都可能适用,但有时讨论模式会使问题更加混乱。

以下是我个人会做的事情:

  1. 在视图层,大量依赖模板。大量使用布局、包含或局部,以便更轻松地组合表示层对象。
  2. 大量使用特定于客户端的配置文件(我很喜欢用YAML进行此目的),以便在不修改核心代码的情况下更轻松地进行自定义。
  3. 在模型和控制器层,选择一些适当的结构模式,使您的对象可以根据客户端特定的配置文件表现出多态性。这里鸭子类型是您的朋友!
  4. 基于主机名或域使用一些内省,为每个客户端启用多态行为。

Git的下一步操作

一旦重构应用程序以最小化客户之间的更改,您可能会发现,除非您试图隐藏每个客户端的多态代码,否则根本不需要将代码分开。如果是这种情况,您当然可以在那时调查子模块或单独的分支,但不需要承担分支之间重复的负担。

符号链接也是您的朋友

最后,如果您发现可以将更改隔离到几个子目录中,Git支持符号链接。您可以在开发分支上的每个客户端子目录中拥有所有不同的代码,并将文件符号链接到每个客户端发布分支的正确位置。您甚至可以使用一些shell脚本或自动部署期间自动化此过程。

这样做可以将所有开发代码放在一个地方,方便比较和重构(例如开发分支),但同时确保真正需要针对每个发布版本不同的代码在推向生产环境时位于正确位置。


更详细地解释一下这个应用程序:我正在使用基于MVC模式的PHP框架。在模型中,基本上没有客户特定的更改,它们是纯平台。控制器目前对用户组的访问权限进行硬编码(因为通过UI使其灵活需要大量工作)。视图总是有些不同,小的格式、颜色,以及不同类型的可视化。这也可能会再次影响控制器处理不同的信息。但如果深入研究这个问题,我们应该开另一个话题... - Achim
1
我按照您的建议CodeGnome,编写了一个脚本,可以将自定义目录中的所有文件符号链接到正确的位置。 这样,我将保持源代码树的清洁,使用git树内的自定义子目录和指向当前构建文件的符号链接,这不应该改变我的git状态。 这是我的代码要点 - mico

2

由于你需要为每个供应商定制解决方案,因此供应商分支是最合理的选择。最好的方法是放弃这种方式,开发多租户应用程序


网站托管在小型嵌入式控制器上。每个客户都安装了几十个这样的控制器,所有控制器都具有相同的网站,仅在配置和连接机械方面略有不同。 - Achim
另一个客户在他的控制器上有不同的网站,但我没有一个能够托管多租户应用程序的中央大型服务器... - Achim
您可以使用相同的策略,并通过许可证密钥激活不同的功能。 - Adam Dymitruk
假设我提供了10个客户,每个客户对平台有20%的差异。因此总共会累积到平台上增加200%的代码,这在每个嵌入式控制器上都太昂贵了。此外,即使我不激活,我也不想将客户A的代码放在客户B的控制器上。 - Achim
然后制作一个安装程序,允许某些功能或行为开启或关闭。 - Adam Dymitruk

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