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

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教程】(十七)发行版交付 — 概述及使用要求,执行过程及其实现,替代解决方案 ~》

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/627924.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis-持久化操作-AOF

持久化操作-AOF AOF是什么? 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只允许加文 件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之…

git入门操作

一、介绍 Git是一个开源的分布式版本控制系统,由Linus Torvalds创建,用于有效、高速地处理从小到大的项目版本管理。 二、注册Git代码托管平台账号 以下几个平台可供选择: Gitee: https://gitee.com/(国内) Gitee(码云&…

从丢失到找回:手机相册恢复实战教程

“之前因为手机延迟把三千多张相片都删了,花了几个小时找文档,最后也没找到。对于爱拍照的朋友来说,照片被误删或不见真的会超级难过!请问大家有什么好方法能够恢复照片吗?” 在数字时代,手机相册成为了我…

PLC的ST语言实现IIR butterworth低通滤波器

参考 Butterworth Filter Design in C – The Code Hound matlab代码,创建一个fc0.1的4阶butterworth低通滤波器。 format long[b,a] butter(4,0.1,low)input1 [1,2,3,1,2,3,1,2,3,0,0]; output filter(b,a,input1)过滤input1的结果为 output Columns 1 throu…

嵌入式基础课程配套电机FOC伺服电机开发板AT32F403磁编码IMU姿态

嵌入式基础课程配套电机FOC伺服电机开发板AT32F403磁编码IMU姿态 带你入门嵌入式有二十多年开发经验的老技骨做技术支持整个开发包硬件包括电机2205,支持12V到24V宽输入,配套12V2A电源。包装原理图和PCB嵌入式软件嵌入式基础课程 带你入门嵌入式 电机FO…

免费SSL证书怎么签发

大家都知道SSL证书好,作用大,安全性高,能加权重,等保必须的参考值。但是如何选择合适且正确的证书也是至关重要的,网站更适合单域名证书、多域名证书、泛域名证书、还是多域名通配符证书。 首先大家要清楚&#xff0c…

MATLAB车辆动力学建模 ——《控制系统现代开发技术》

引言 在上这门课之前,我已经用过CasADi 去做过最优化的相关实践,其中每一步迭代主要就是由:对象系统优化求解两部分组成的。这里我们重点介绍 “对象系统”如何去描述 ,因为它是每一步迭代中重要的一环——“优化求解”会获得控制…

Java逐层解析JSON的内存占用分析

哈喽,大家好,我是木头左! 在当今的软件开发世界中,JSON(JavaScript Object Notation)已经成为了数据传输和存储的事实标准。由于其轻量级且易于人类阅读的特点,JSON被广泛用于Web服务、移动应用…

【制作100个unity游戏之26】unity2d横版卷轴动作类游戏5(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言三段攻击攻击设置只对敌人造成伤害限制可以移动攻击问题 角色连续按四下攻击,最后会多a一下问题:站在原地连续攻击野猪,只有第一下攻击野猪才掉血,后面的攻击野猪不掉血源码完结 …

一图流解释Java中线程状态的转换

目录 一.Java中的几大线程状态 二.线程之间的相互转换 ▐ NEW --> RUNNABLE ▐ RUNNABLE <--> WAITING ▐ RUNNABLE <--> Timed Waiting ▐ RUNNABLE<--> BLOCKED ▐ RUNNABLE<-->TERMINATED 一.Java中的几大线程状态 简单来说线程可以处于…

美团小程序mtgsig1.2逆向

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

网络安全等级保护在工业控制系统中的应用

工业控制系统(Industrial Control Systems,ICS)&#xff0c;是由各种自动化控制组件和实时数据采集、监测的过程控制组件共同构成。其组件包括数据采集与监控系统(SCADA)、分布式控制系统(DCS)、可编程逻辑控制器(PLC)、远程终端(RTU)、智能电子设备(IED)&#xff0c;以及确保各…

C语言单向链表、双向链表和循环链表有什么区别?

一、问题 链表分为单向链表、双向链表和循环链表&#xff0c;它们的不同之处是什么呢&#xff1f; 二、解答 &#xff08;1&#xff09;单向链表。 所谓单向链表&#xff0c;就是指数据结点是单向排列的。⼀个单向链表结点由两个域组成&#xff0c;存储在结构体类型中。⼀个域…

从零开始:利用美颜API打造属于你的直播美颜功能

当下&#xff0c;如何在直播中呈现最好的自己&#xff0c;成为了许多主播关心的问题。美颜功能应运而生&#xff0c;帮助主播们在镜头前展现更好的形象。本文将详细介绍如何从零开始&#xff0c;利用美颜API打造属于你的直播美颜功能。 一、认识美颜API 1、什么是美颜API 美…

用wxPython和PyMuPDF将PNG图像合并为PDF文件

在日常工作中,我们经常需要将多个图像文件合并到一个PDF文档中,以便于查看、共享或存档。虽然现有的一些工具可以实现这一功能,但开发一个自定义的GUI工具可以更好地满足特定需求,并提供更好的用户体验。 在本文中,我将介绍如何使用Python、wxPython和PyMuPDF库创建一个简单的…

【java】异常与错误

Throwable包括Error和Expected。 Error Error错误是程序无法处理的&#xff0c;由JVM产生并抛出的。 举例&#xff1a;StackOverflowError \ ThreadDeath Expected Expected异常包括两类&#xff0c;即受检异常(非运行时异常)和非受检异常(运行时异常)&#xff0c;异常往往…

两大DRAM巨头20%产能转给HBM

随着人工智能(AI)需求的激增&#xff0c;全球领先的内存芯片制造商三星(Samsung)和SK海力士(SK Hynix)预计&#xff0c;由于高性能芯片需求不断增长&#xff0c;今年DRAM和高带宽内存(HBM)的价格将保持强劲。据《韩国经济日报》报道&#xff0c;三星和SK海力士已将其超过20%的D…

BUUCTF靶场[MISC]荷兰宽带数据泄露、九连环

[MISC]荷兰宽带数据泄露 考点&#xff1a;查看路由器恢复丢失密码的文件 工具&#xff1a;RouterPassView——路由器密码查看工具 工具链接&#xff1a;https://routerpassview.en.lo4d.com/windows RouterPassView是一款老牌的路由器密码查看器&#xff0c;可以一键获取路…

网络安全从业者“行话”

目录 ​编辑 一、攻击篇 1&#xff0e;攻击工具 2&#xff0e;攻击方法 3&#xff0e;攻击者 二、防守篇 1&#xff0e;软硬件 2&#xff0e;技术与服务 网络安全学习资源分享: 特别声明 一、攻击篇 1&#xff0e;攻击工具 肉鸡 所谓“肉鸡”是一种很形象的比喻&…

JavaScript循环结构

JS循环结构 1 while结构2 for循环3 foreach循环 1 while结构 几乎和JAVA一致 代码 /* 打印99 乘法表 */var i 1;while(i < 9){var j 1;while(j < i){document.write(j"*"i""i*j" ");j;}document.write("<hr/>");i…