首页 > 其他分享 >Git 工具 - 子模块: submodule与subtree的使用

Git 工具 - 子模块: submodule与subtree的使用

时间:2023-04-09 23:15:10浏览次数:53  
标签:Git 仓库 subtree submodule git 模块

git日常使用中,基本都是一个项目一个Git仓库的形式,那么当我们的代码中碰到了业务级别的需要复用的代码,我们一般怎么做呢?

比如:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。

所以需要提取一个公共的类库提供给多个项目使用,但是这个library怎么和git在一起方便管理呢?

现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。

我们大致的考虑一下,一般有两种方案:

  1. 抽象成NPM包进行复用;

  2. 使用Git的子仓库对代码进行复用;

但是:两个程序中有部分页面或功能是重叠的,在前端领域,比如AntDesign、element-UI,react 、vue、angular版本样式是一样的,只是组件不同。

开发过程中重叠部分如果开发两套代码会浪费不少的人力。

个人推荐选用Git子模块的方式进行开发,父级仓库依赖两个公共的子模块,子模块本身和父级仓库一同进行开发,可避免了版本问题和重复开发的问题

面对比较复杂的项目,我们有可能会将代码根据功能拆解成不同的子模块。主项目对子模块有依赖关系,却又并不关心子模块的内部开发流程细节

大致结构可能是这样

project

|--moduleA

|--submoduleC

|--submoduleD

|--moduleB

project和ABCD各个模块中,CD在不同的git仓库中,这时,就需要使用git的的模块功能

Git 工具 - 子模块

Git 通过子模块来解决这个问题。 子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。

通俗上的理解, 一个Git仓库下面放了多个其他的Git仓库,其他的Git仓库就是我们父级仓库的子仓库。

git Submodule 是一个很好的多项目使用共同类库的工具,他允许类库项目做为repository,子项目做为一个单独的git项目存在父项目中,子项目可以有自己的独立的commit,push,pull。而父项目以Submodule的形式包含子项目,父项目可以指定子项目header,父项目中会的提交信息包含Submodule的信息,再clone父项目的时候可以把Submodule初始化。

可以端详官网:https://git-scm.com/book/zh/v2/Git-工具-子模块

多个父级仓库都依赖同一个子仓库,但是子仓库自身不单独进行修改,而是跟随父级项目进行更新发布,其他依赖子仓库的项目只负责拉取更新即可

Git两种子仓库使用方案

  1. git submodule

  2. git subtree

git submodule(子模块)

Git子模块允许我们将一个或者多个Git仓库作为另一个Git仓库的子目录,它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立

在Git 中你可以用子模块submodule来管理这些项目,submodule允许你将一个Git 仓库当作另外一个Git 仓库的子目录。这允许你克隆另外一个仓库到你的项目中并且保持你的提交相对独立。

开始使用子模块
git clone https://github.com/zhoulujun/zhoulujun.cn-phpcms.git zhoulujun
cd  zhoulujun
git submodule add   tools 
git submodule add  https://github.com/zhoulujun/zhoulujun.cn-tools-vue.git tools-vue

添加子模块后运行git status, 可以看到目录有增加1个文件.gitmodules, 这个文件用来保存子模块的信息。

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   .gitmodules
    new file:   assets

 

使用git init --bare在本地创建两个裸仓库,分别表示主仓库和依赖的子仓库,我们将主仓库命名为main,依赖的子仓库命名为lib, git subtree使用同样的初始化方法,下文不再赘述。

git submodule常用命令

  • 查看子模块:git submodule

  • 更新子模块:

    • 更新项目内子模块到最新版本:git submodule update

    • 更新子模块为远程项目的最新版本:git submodule update --remote

  • 克隆包含子模块的项目:

    • 克隆父项目:git clone https://github.com/demo.git assets

      • 初始化子模块:git submodule init

      • 更新子模块:git submodule update

    • 递归克隆整个项目submodule:git clone https://github.com/demo.git assets --recursive 

    • 递归更新整个项目submodule:git submodule foreach git pull

  • 删除子模块:git rm --cached subModulesA    rm -rf subModulesA

--recursive表示递归地克隆git_parent依赖的所有子版本库。

git subtree(子树合并)

上面介绍的git submodule是Git自带的原生功能,我们接下来将要介绍的git subtree则是由第三方开发者贡献的contrib script,Git本身并不提供git subtree命令,contrib中包含一些实验性的第三方工具,由各自的作者进行维护。

同时这也让我们认识到git subtree不是Git原生支持的命令,而是第三方开发者通过Git的底层命令写出的一个高层次脚本,所以它是可以由基础的Git命令来实现的。

git子仓库submodule与subtree区别

subtree与submodule的作用是一样的,但是subtree出现得比submodule晚,它的出现是为了弥补submodule存在的问题:

  1. submodule不能在父版本库中修改子版本库的代码,只能在子版本库中修改,是单向的;

  2. submodule没有直接删除子版本库的功能;

subtree则可以实现双向数据修改。官方推荐使用subtree替代submodule

这里就先不提了

使用Git subtree命令

  • 创建本地目录

    • 语法:`git remote add  <子仓库名> <子仓库地址>`

    • 实例:`git remote add component [email protected]`

  • 添加远程仓库(本地存在文件目录)

    • 语法:`git remote add -f <子仓库名> <子仓库地址>`

    • 实例:`git remote add -f component [email protected]`

  • 使用 ( pull & push )

    • pull:`git subtree pull --prefix=component component master --squash`

    • push:`git subtree push --prefix=component component master --squash`

注意:**必须在 `component` 的父级目录执行**,使用起来还不是很方便。

submodule可以一起clone出来,只需添加--recursive递归参数就可以了,而subtree并不行,只能手动添加

个人使用submodule习惯了,所以天然觉得subtree复杂难用===难道就像用惯了intelliJ,就没有心思去用VScode了,哈哈!

有人对 submodule 和 subtree 的区别做的一个总结还是挺形象的: submodule is link; subtree is copy 

更多的推荐阅读: Git应用详解第十讲:Git子库:submodule与subtree https://blog.csdn.net/qq_43425487/article/details/105632114

 

Git的子仓库原理分析

如果不是很了解底层原理,很可能会导致使用子仓库出现云里雾里的现象,搞不清楚是父级仓库先提交,还是子仓库先提交

git submodule原理分析

我们知道Git底层大致依赖了四种对象,构成了Git对于文件内容追踪的基础:

  • blob: 二进制大文件,可以通俗理解为对文件的修改

  • tree: 记录了blob对象和其他tree对象的修改,通俗理解为目录

  • commit: 提交对象,记录了本次提交的tree对象和父类的commit对象以及我们的提交信息

  • tag: 我们对当前提交记录版本的对象

更加详细的内容请参考《深入理解Git

我们此处需要依赖一个print_all_object的工具函数,它会帮助我们将git仓库下的这四种对象按照反向提交历史的排序展现出来,可以将它放在环境变量下方便全局使用:

#!/bin/bash

print_all_object() {
  for object in `git rev-list --objects --all | cut -d ' ' -f 1`; do
    echo 'SHA1: ' $object
    git cat-file -p $object
    echo '-------------------------------'
  done
}

print_all_object

我们在main仓库下执行print_all_object:

# 此时处于我们刚对子模块提交的那个时间点
# 对部分长的hash进行了截取处理,不影响阅读观感
print_all_object

SHA1:  a1cfd26e
tree c77ba9c2
parent ab118b8

feat: 增加子仓库依赖
-------------------------------
SHA1:  ab118b8
tree f5771cd

feat: 父级仓库创建index.js
-------------------------------
SHA1:  c77ba9c2
100644 blob d8c9fb4    .gitmodules
100644 blob ddd81ae    index.js
160000 commit 40f8536  lib
-------------------------------
SHA1:  d8c9fb4
[submodule "lib"]
        path = lib
        url = /path/to/repos/lib.git
-------------------------------
SHA1:  ddd81ae
console.log('main');-------------------------------
SHA1:  f5771cd
100644 blob ddd81ae    index.js
-------------------------------

 

index.js文件是blob对象,对应的file mode是100644,但是对于lib子仓库的确是一个commit对象, file mode为160000,这是Git中一种特殊的模式,表明我们是将一次提交的commit记录在Git当中,而非将它记录成一个子目录或者文件。

而这正式git submodule的核心原理,Git在处理submodule引用的时候,并不会去扫描子仓库下的文件的变化,而是取子仓库当前的HEAD指向的commit的hash值,当我们对子仓库进行了更改后,Git获取到子模块的commit值发生变化,从而记录了这个Git指针的变化。

在暂存区所以我们才发现了new commits这种提示语,Git并不关心子模块的文件如何变化,我只需要在当前提交中记录子模块的commit的hash值即可,之后我们从父级仓库拉取子仓库的时候,Git拉取了本次提交记录中的子模块的hash值对应的提交,就还原了我们的整个仓库的代码。

git submodule注意点

虽然使用git submodule为我们的开发带来了很多便利,但是随之而来也会导致一些比较容易犯的错误,整理出来,防止大家采坑:

  1. 当子模块有提交的时候,没有push到远程仓库, 父级引用子模块的commit更新,并提交到远程仓库, 当别人拉取代码的时候就会报出子模块的commit不存在 fatal: reference isn’t a tree。

  2. 如果你仅仅引用了别人的子模块的游离分支,然后在主仓库修改了子仓库的代码,之后使用git submodule update拉取了最新代码,那么你在子仓库游离分支做出的修改会被覆盖掉

  3. 我们假设你一开始在主仓库并没有采用子模块的开发方式,而是在另外的开发分支使用了子仓库,那么当你从开发分支切回到没有采用子模块的分支的时候,子模块的目录并不会被Git自动删除,而是需要你手动的删除了。

 

 

参考文章:

Git submodule 子模块的管理和使用 https://www.jianshu.com/p/9000cd49822c

使用Git Submodule管理子模块 https://segmentfault.com/a/1190000003076028

Git子仓库深入浅出 https://juejin.im/post/6844904034722119694

子模块 http://gitbook.liuhui998.com/6_2.html

使用git subtree & submodule管理多个子项目 https://www.jianshu.com/p/84e34ac318e4

 Git应用详解第十讲:Git子库:submodule与subtree https://blog.csdn.net/qq_43425487/article/details/105632114

git submoudle vs git subtree https://efe.baidu.com/blog/git-submodule-vs-git-subtree/

 

 

 


转载本站文章《Git 工具 - 子模块: submodule与subtree的使用》,
请注明出处:https://www.zhoulujun.cn/html/tools/VCS/git/8566.html

标签:Git,仓库,subtree,submodule,git,模块
From: https://www.cnblogs.com/zhoulujun/p/17301382.html

相关文章

  • head/reset/revert/rebase代码回滚全解:git提交记录的背后原理
    多人合作程序开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子,操作有:回退(reset):reset是彻底回退到指定的commit版本,该commit后的所有commit都将被清除;reset执行后不会产生记录反转(revert):revert仅是撤销指定commit的修改,并不影响后续......
  • GitHub Pulse 是什么?它是否能衡量 OpenTiny 开源项目的健康程度?
    Pulse是“脉搏”的意思,就像一个人要有脉搏才能算是一个活人,一个开源项目要有“脉搏”才能算是一个“活”的开源项目,这个单词非常形象地表示了开源项目的健康程度。脉搏是正常的,开源项目才是健康的。每个开源项目的Pluse数据都是公开的,它位于开源项目代码仓库的Insights页......
  • git stash|4-6
    应用场景1当正在dev分支上开发某个项目,这时项目中出现一个bug,需要紧急修复,但是正在开发的内容只是完成一半,还不想提交,这时可以用gitstash命令将修改的内容保存至堆栈区,然后顺利切换到hotfix分支进行bug修复,修复完成后,再次切回到dev分支,从堆栈中恢复刚刚保存的内容。2由于疏忽,本......
  • Vulnhub:Digitalworld.local (Development)靶机
    kali:192.168.111.111靶机:192.168.111.130信息收集端口扫描nmap-A-v-sV-T5-p---script=http-enum192.168.111.130查看网站首页源码访问development目录,提示存在一个流量包查看流量包发现另一个网站路径:/developmentsecretpage/directortestpagev1.php访问该路......
  • git设置代理
    背景国内提交代码到github,因为网络原因很蛋疼~需要设置代理,才能正常且快速的提交代码。刚巧我有国外的云服务器,自己搭建了一个socket5代理。设置代理命令设置代理gitconfig--globalhttps.proxy"socks5://ip:1080"#socksgitconfig--globalhttp.proxy'socks5://127......
  • Question1:如何在Git中撤销最近的commit并重新执行add操作?「有问必答」
    你好,我是悦创。这是有问必答系列,你可以把你的问题在文章下评论,无论什么问题,我都会为你解答。如果你想撤销最近的一次提交并将更改重新放回暂存区(stagingarea),可以使用如下命令:gitreset--softHEAD^这将撤销最近的一次提交,同时保留更改在暂存区。之后,你可以使用gitadd将你想要......
  • 【转】git 合并某个分支上某次commit记录到另外一个分支
     转,原文:https://www.cnblogs.com/wjxbk/p/15469212.html------------------------------ git合并某个分支上某次commit记录到另外一个分支 需求:需要将A分支的某次提交记录,合并到B分支 解决步骤:1)gitcheckoutA分支找到提交的commitid可以使用gitlog命令......
  • GitHub Actions:从使用action操作到自定义action操作
    (目录)1、使用action操作文档https://docs.github.com/zh/actions/quickstart.github/workflows/github-actions-demo.ymlname:GitHubActionsDemorun-name:${{github.actor}}istestingoutGitHubActions......
  • Git 新手使用学习手册
    目录一、Git概述1.Git介绍2.Git安装二、Git分区1.三大分区和三大状态(1)存储三大分区(2)文件三大状态2.分区转换指令2.分区对比指令三、Git配置1.用户配置2.远程仓库配置(1)生成SSHkey(2)GitHub上添加SSHkey四、Git本地操作1.创建本地仓库2.版本回退(1)以版本号实现(2)以标签实现3.......
  • 利用github作为文档类云盘
    初次使用创建一个github仓库在本地新建文件夹,clone远程仓库 更新本地文档上传本地文档发生更改,gitadd,gitcommit进行上传本地仓库,然后push到远程仓库 远程仓库文档发生更新,更新到本地仓库只能和初次使用一样进行clone......