【Git教程】(十八)拆分大项目 — 概述及使用要求,执行过程及其实现,替代解决方案 ~

server/2024/11/14 13:14:27/

Git教程 · 拆分大项目

  • 1️⃣ 概述
  • 2️⃣ 使用要求
  • 3️⃣ 执行过程及其实现
      • 3.1 拆分模块版本库
      • 3.2 将拆分出的模块作为外部版本库集成
  • 4️⃣ 替代解决方案

在这里插入图片描述

通常软件项目都是由单体小型系统开始的,在开发过程中项目规模和团队人员不断扩大, 将项目模块化会显得越发重要。第一步是将项目内部结构模块化,最终会需要将各个模块独立开发并拥有不同的提交发布周期。

由于 Git 版本库是以整个版本库作为一个整体来发布版本的,所以每个拥有独立发布周期的模块都需要新的Git 版本库。
为 Git 版本库拆分模块过程中的挑战之处在于要尽可能保留原版本库中文件及其版本信息。同时,新的版本库不应该包含本模块不需要的文件,也不需要包含那些没有更改本模块相关文件的提交。

在主版本库中,模块的历史没有被删除,所以原项目中的历史版本已然存在并可以复现。因此,不同模块的历史数据同时存在于拆分前后两个版本库中。
大部分拆分出的模块依然被主项目所需要,应以外部模块的角色集成到主项目中,这种集成关系,在Git 中被称为子模块 (submodule)。

这段工作流演示了如何在Git 中抽取模块,同时实现这样3种目标。

  • 只有该模块所需要的文件被导入到新版本库。
  • 模块文件历史将被保留在新版本库中。
  • 模块可以作为外来模块再次被集成到主项目中。

1️⃣ 概述

接下来这段操作中,我们使用如图上部显示的项目结构为例。这段实例工作流是基于Java 目录结构的,整个项目有3个模块,每个模块中的文件分别置于源代码 (src) 和测试代码 (test) 两个子目录中。换句话说,也就是每个模块包括两个部分。接下来将模块3分化到独立的版本库中。

第一步,删除所有无用的文件,使用 filter branch 命令在原版本库的一个克隆分支上提交即可。接下来,更新新模块版本库的目录结构用以管理模块3。最后,将模块3从原项目中移除,再将新模块版本库作为子模块合入原项目的外部引用目录中,结果如图下部所示。

在这里插入图片描述
新的模块版本库中可以重建文件的修改历史,也就是跟踪记录谁在什么时间做了什么修改,但是不可以完整地重现历史版本。原因是一个模块的文件往往源自另外一些模块。在模块版本库中尝试恢复项目的某一历史版本可能不仅会涉及本模块目录,而是不同目录文件的混杂集合。而且,在过去的版本中本模块可能被用作某些文件的依赖,而这些文件已经不存在了。
在主版本库中,整个项目的旧版本依然可以恢复重现。


2️⃣ 使用要求

  • 项目内部需要模块化时:项目内部需要被分为不同的模块,比如当某一模块需要独立开发和发布版本。
  • 模块文件被分置于不同的目录中时:这时要提取模块的某一历史版本,文件在不同个目录中将需要不同的处理,如果文件十分分散代价将非常大。

3️⃣ 执行过程及其实现

一个模块从项目中被删除并迁移到独立的版本库中,提交历史将被保留下来,无用的文件和提交历史将被删除。独立模块将以外部子模块的形式回到项目中。

需要注意,部分以下命令将彻底改变版本库。虽然 Git 中改变通常可以撤回,但仍应在开始之前确保你的版本库已备份。

> git clone --no-hardlinks --bare projekt.git projekt.backup.git

使用 --no-hardlinks 选项来保证克隆的版本库和源版本库不共享任何文件。


3.1 拆分模块版本库

  • 第1步:克隆主版本库
    作为模块版本库的起点,首先将主版本库克隆一份。

    > git clone --no-hardlinks --bare projekt.git modul3-work.git
    
  • 第2步:删除无用的文件和提交
    接下来,必须删除无用的文件和提交,这是最复杂的一步,也是为了保留模块历史至关重要的一步。
    删除一个版本库中的部分内容可以用 filter-branch 命令。它将针对待修改的提交来创建一次新的提交,通过配置不同的过滤器来改变这次提交的内容。
    以下示例 filter-branch 命令将删除 src/module1 目录下内容。

    > cd module3
    > git filter-branch --force --index-filter
    'git rm -r -cached --ignore-unmatch src/module1'--tag-name-filter cat--prune-empty -- --all
    

    参数可以这样配置。

    • --index-filter 'git rm -r -cached --ignore-unmatch …': 通过配置这样的参数,可以将文件从提交中移除。rm 命令逐个提交操作。在如上示例中,将作用于src/module1文件目录。 如果待清理的项目没有明显的模块化结构层次,可能需要删除多个文件或多个文件目录。
    • --tag-name-filter cat: 可以为已经存在的或者新建的提交标注标签。
    • --prune-empty: 将删除经过前面的过滤器后不包含任何文件的空提交。
    • --all: 将过滤器适用于整个项目的所有分支。
      在示例的项目中,如此的操作需要依次在 test/module1 、src/module2 和 test/module2 文件目录下执行。
      关于 filter branch 命令每项参数的详细描述,可以参照 Git 帮助。
  • 第3步:删除无用的分支和标签
    不是所有标签和分支在新的模块分支都有意义。例如,那些与模块不相关的文件标签和分支就是无意义的,需要被删除。

    > git tag -d v1.0.1
    > git branch -D v2.0_bf
    
  • 第4步:缩减模块版本库的规模
    Git 为了缩减规模在管理数据中删除无用的文件需要重复克隆一次。

    > git clone --no-hardlinks
    --bare module3-work.git module3.git
    

    这样,过去的模块版本库 module3-work.git 就不再有效,可以删除了。

    > rm -rf modul3-work.git
    
  • 第5步,定制模块版本库文件架构
    到目前为止,新版本库的文件结构和主项目一样,只是删除了无关本模块的文件。调整文件目录结构是通过一般的文件操作完成的,为了这个目的,首先应做一份带有工作空间的克隆。

    > git clone module3.git module3
    

    将源代码目录 src/module3 重命名为 src , 测试代码目录 test/module3 重命名为 test

    > cd module3
    > mv src/module3 module3
    > rmdir src
    > mv module3 src
    > mv test/module3 module3
    > rmdir test
    > mv module3 test
    

    接下来,修改操作通常是借助于commit 命令,再通过 push 上传到干净的版本库中。

    > git add --all
    > git commit -m "Directory structure adapted"
    > git push ,
    

    如果版本库中有多个分支,那文件操作要在各个分支上依次完成。 .
    通常没有必要保留主项目所有的分支。新的版本库有新的分周期,旧分支通常没有意义。

  • 第6步:在主项目中删除已被拆分出来的模块目录
    当拆分出的模块已迁移到新的版本库中,下一步就是让主项目来做拆分后的调整。删除 无用的源代码目src/module3 和测试目录 test/module3。这里的调整主要是在主版本库中的一些普通的文件操作。

    如果项目中有多个分支需要集成这一个改变,那也需要分别进行调整。cherry-pick 命令可以用作将变化调整部署到不同的分支。


3.2 将拆分出的模块作为外部版本库集成

经过前面一系列操作,现在已经拥有两个版本库了,通常原主项目仍需引用拆分后的模块,所以需要集成操作。
集成操作严格依赖于开发平台。例如在 Java Maven项目中,可以将拆分出的模块项目独 立创建编译,并将结果保存在 Maven 项目中,在主项目中将其定义为依赖条件,在创建编译主项目的过程中充 Maven 中获得模块项目。

如果使用 Git 来执行集成操作,那就需要用到子模块 (submodule) 。 有了子模块, 一个Git版本库就可以链接到另外一个 Git版本库了。

在上述示例中,模块3 (module3) 的版本库被链接到了主项目的extern/module3 文件目录下。首先从主项目版本库的一个克隆版开始操作。选定项目的根目录,使用 submodule add 命令加入子模块,该命令有两个参数,第一个是模块版本库的路径或 URL, 第二个参数是在主项目中即将链接的路径。

>git submodule add /global-path-to/module3.git extern/module3

submodule add 命令会在特定的目录下创建一个模块版本库的克隆,这个克隆会在主版本库中作为外部引用。
文件目录 extern/module3 指向外部版本库的最新一次提交 (HEAD) 。
截至目前,子模块只能在工作区中可见,需要只用 commit 命令提交使修改作用于整个版本库。

>git add -all
>git commit -m "Modul3 added"

可以使用 push 命令将添加子模块链接捷径的修改推送到中央版本库。


4️⃣ 替代解决方案

  • 何不采用一个全新的版本库
    有另外一种可以考虑的替换方案是简单地为模块创建一个新版本库。那么,新版本库中就没有原模块的历史记录了,但是原始版本库中仍然有模块的旧版本信息。如果这种缺陷可以被接受,那这种方案在实现上显得最为简单。

  • 为什么不采用 --subdirectory-filter 选项
    使用 filter-branch 命令和 -index-filter 参数可以实现将提交中的文件删除。
    filter-branch 命令的 --subdirectory-filter 参数可以指定将排除某一文件夹之外的文件全部删除,还可以在删除指定的文件夹后改变项目的根目录节点。

    只要模块全部独立存储在一个文件目录下,那么这个命令就可以较方便地用来创建模块版本库。在上文示例中,模块文件被分散在两个目录下,因此不能适用这样的操作。

    即使模块中的文件所属文件目录被迁移或者被改名, subdirectory-filter 仍然可以保留部分历史信息。



温习回顾上一篇(点击跳转)
《【Git教程】(十七)发行版交付 — 概述及使用要求,执行过程及其实现,替代解决方案 ~》

继续阅读下一篇(点击跳转)
《》


http://www.ppmy.cn/server/41812.html

相关文章

idea使用gitee基本操作流程

1.首先,每次要写代码前,先切换到自己负责的分支 点击签出。 然后拉取一次远程master分支,保证得到的是最新的代码。 写完代码后,在左侧栏有提交按钮。 点击后,选择更新的文件,输入描述内容(必填…

正则表达式和lambda表达式

正则表达式(Regular Expressions)和Lambda表达式虽然都包含“表达式”一词,但它们在编程中的作用和用法是完全不同的。让我们详细比较一下它们的定义、用途和应用场景: 正则表达式 定义:正则表达式是一种用于匹配文本…

知识分享|XDC时钟约束的详细说明

在FPGA设计中,时钟约束是确保设计满足时序要求的关键。Xilinx Design Constraints (XDC) 文件允许设计者对时钟、输入/输出(I/O)和跨时钟域(CDC)路径进行精确的时序约束。以下是XDC文件中时钟约束的详细说明: 时钟约束的重要性 时钟约束必须最早创建&a…

业务上云--从Container+BuildKitd打镜像到在Kubernetes上部署LNMP

一、背景 在基于kubeasz部署kubernetes高可用集群-CSDN博客文章部署的kubernetes集群上部署LNMP 1.1、Kubernetes环境 1.2、Harbor环境 【docker基础】使用Harbor搭建私有仓库-docker-compose使用示例--第二周作业_harbor docker-compose-CSDN博客 Harbor环境升级&#xff…

音视频-H264编码封装- MP4格式转Annex B格式

目录 1:H264语法结构回顾 2:H264编码补充介绍 3:MP4模式转Annex B模式输出到文件示例 1:H264语法结构回顾 在之前文章里介绍过H264的语法结构。 传送门: 视音频-H264 编码NALU语法结构简介 2:H264编码补充介绍 H…

什么是Java中的设计模式?请列举几种常见的设计模式

一、引言 在软件开发中,设计模式是解决特定设计问题的最佳实践或通用解决方案。Java作为一种广泛使用的编程语言,其设计模式在软件设计和架构中起着至关重要的作用。设计模式不仅提高了代码的可读性和可维护性,还使得代码更加灵活和可扩展。…

IT行业的现状与未来发展趋势:探索无限可能

随着技术的不断进步,IT行业已成为推动全球经济和社会发展的关键力量。从云计算、大数据、人工智能到物联网、5G通信和区块链,这些技术正在重塑我们的生活和工作方式。在本篇博客中,我们将探讨IT行业的现状以及未来发展趋势,展望这…

Git篇——Git提交指定文件编码

背景:项目中有些老工程的代码编码格式不统一,可以通过以下方式强行指定提交时的文件编码,可以将所有上传到git的文件的编码格式统一。 在Git中,可以通过设置.gitattributes文件来指定文件编码。在项目根目录下创建一个名为.gitat…