Git详解:使用Git子模块构建项目伞形结构
开发团队经常会面临这样的抉择:如何构建 Git 结构来管理项目的不同部分。有些团队选择单体仓库(monorepo),而有些团队则选择将其拆分成多个子项目,例如,一个仓库用于 UI,另一个仓库用于 API。这两种 Git 结构各有优缺点。
单体仓库(Monorepo)具有代码共享、减少代码重复、单一构建和原子提交等优势。然而,单体仓库也存在提交过多、提交分散在代码树不同部分的问题,并且在克隆、获取和推送代码时可能出现性能问题。另一方面,维护子项目意味着需要克隆多个仓库,需要遵循多套安装和构建指令,以及需要管理多个目录。
最近,我接触到了Git 子模块,它可以用来创建一个指向 UI 和 API 外部仓库中特定提交的中心伞形仓库。这种伞形结构允许你保留子项目组合,同时又具备单体仓库的一些优势,例如在一个中心位置管理文档和配置,以及能够一步拉取整个项目(包括子项目)。本文将探讨使用 Git 子模块构建伞形仓库结构的优势、遇到的挑战,以及你需要学习哪些命令才能开始使用这种 Git 结构。
好处
子项目组成。为项目的不同部分创建多个代码库,可以让你根据“实际需要”来限制访问权限。例如,假设你团队中新加入了一位前端开发人员,以加快 UI 的实现速度。这位开发人员可以轻松地选择只拉取 UI 代码库,而无需修改 API。
持续开发。所提出的基于 Git 子模块的伞形结构保持了子项目组成,使得每个代码库都能拥有自己的部署流程。
文档集中管理。伞形仓库允许您将适用于整个项目的文档集中在一个位置。我个人喜欢在伞形仓库中保留一个全局 Markdown 文件,其中包含使用Docker构建和运行整个项目的说明;同时在每个子仓库中保留一个 Markdown 文件,其中包含如何在本地安装和使用每个子项目的说明。
配置集中管理。我们的团队使用 Docker 容器来创建、部署和运行应用程序。Ultram 仓库是一个绝佳的位置,您可以将一个docker-compose.yml文件放在其中,该文件只需一条命令即可构建并运行数据库镜像、API 和 UI 环境。
原子代码拉取。在克隆伞形仓库时使用该--recurse-submodules标志,即可通过一条命令获取包含子模块的所有嵌套目录。换句话说,您可以一次性获取 UI 和 API 仓库。
斗争
需要在说明中明确 Git 子模块的使用方法。如果您的团队不熟悉这种 Git 结构,他们很可能不知道如何正确克隆或处理子模块。Git 默认情况下不会下载子模块的内容,因此请务必在 README 文件中包含此信息。
手动获取子模块更新。Git不会自动注册子模块的更新。您需要运行命令git submodule update --remote才能查看子模块的更改。
仅提供简单的实现方案。目前,我只使用这种伞形结构来关联每个项目的 UI 和 API 代码库。我明白维护两个以上的子模块可能会比较困难,或许需要您考虑其他实现方式。
这种架构在使用 Docker 时最为有效。如果您不使用 Docker,这种架构的优势可能不会那么明显。
命令
让我们来探讨一下您工具箱中可用于实现这种伞状结构的各种可能性和命令:
创建一个包含子模块的项目
为了更清楚地解释这一操作,我将在 GitHub 上创建一个名为 umbrella 的仓库,以及两个分别名为 umbrella-ui 和 umbrella-api 的仓库。您可以在这里查看它们。
cd[umbrella-project-name]
git submodule add [git@github.com:your-account/umbrella-ui.git] [name]
注意:name 参数是可选的。如果不传递 name 参数,则会使用子模块仓库名称。在本例中,我将 name 参数设置为“ui”,因为我不想在我的“umbrella”项目中出现像“umbrella-ui”这样冗余的目录名称。
运行该ls -a命令后,您会看到一个名为 `<project_name>` 的新目录ui和一个名为 `<modules_name>` 的新文件.gitmodules。该.gitmodules文件是一个配置文件,用于存储主项目及其子模块之间的映射关系。其内容类似于以下内容:
[submodule “ui”]
path = ui
url = git@github.com:your-account/umbrella-ui.git
提交并推送此更改后,您应该会看到一个指向子模块主分支中最新提交的子模块文件夹。
重命名子模块
如果在添加子模块时忘记传递 name 参数,您仍然可以使用以下命令更改子模块目录名称:
git mv [old-name] [new-name]
克隆包含子模块的项目
传递以下命令即可自动克隆您的项目及其子模块。如果您不传递该--recurse-submodules标志,则您的目录将为空。
git clone --recurse-submodules [git-repo-url]
在子模块中工作
这和处理普通代码仓库的流程一样。你进行修改,提交更改,然后推送到远程仓库。
检查子模块更新
当子模块的更改被推送到远程存储库时,您需要检查这些更改并更新您的伞形存储库,因为提交指针将过时。
为了确保你理解这个概念,我将向你展示这个umbrella-api代码仓库,它已经更新,master 分支上的最后一次提交是:6302c8…
现在我们来看一下总仓库,子api模块并没有指向最新的提交umbrella-api,而是指向了一个较旧的提交。15a146…
您可以使用以下命令直接从总目录拉取所有子模块中的更改:
// fetch all new updates in submodules
git submodule update --remote
// see which submodule has been modified
git status
// see all new commits that have been pulled down
git diff
使用最新的子模块提交更新伞形项目。
现在我们已经拉取了子模块中的更改,接下来需要更新主项目的指针。这一点非常重要,因为如果有人在这个状态下克隆我们的主项目,他们将无法获取子模块下的最新代码。
// add all submodules changes
git add .
// commit new pointers
git commit -m “Update submodule pointers”
// publish the changes
git push origin master
注意:您还可以使用以下快捷方式拉取子模块的最新更改,并使您的伞形项目指向最新的提交。
git submodule update --remote --merge
现在我们的伞形项目指向了子模块 umbrella-ui 和 umbrella api 中的最新提交。
你之前在类似的伞形结构中使用过 Git 子模块吗?如果没有,我希望它能引起你的兴趣,让你尝试一下。
感谢您阅读、点赞和分享我的 Git 详解系列文章,这对我意义重大。我非常享受创作这些文章的过程,也十分感谢您提出的问题和建议。
欢迎查看我的其他 Git 讲解文章,并关注下一篇。我每周六都会探索、定义和解释 Git 的概念!
文章来源:https://dev.to/milu_franz/git-explained-an-umbrella-struct-using-git-submodules-20dl






