zoukankan      html  css  js  c++  java
  • git submodule

    参考

    https://blog.csdn.net/zajin/article/details/89042509

    https://blog.csdn.net/breavo_raw/article/details/101857235


    前言
    工作中碰到这样一个场景,一个项目里面的代码分为基础代码和定制化代码,定制化代码是针对不同客户的,基础代码需要和定制化代码分开管理,部署的时候是作为一个项目一起跑的。

    我们在这里使用git submodule功能来尝试解决代码的管理问题。

    功能介绍
    submodule 目前对 git 仓库拆分的已有实现之一。
    它允许将一个Git仓库作为另一个Git仓库的子目录。能够将另一个仓库克隆到自己的项目中,同时还保持独立的提交。

    功能听上去非常的牛逼,那我们赶紧来试用一下吧!

    使用
    准备工作
    我们将在Github上进行相关功能的操作,并在操作过程中时刻观察仓库状态的变化,加深理解。

    首先确保自己有GitHub的账号哈~

    在github新建两个仓库
    很简单,像这样

    我这里直接使用github新建了一个仓库作为主仓库。
    依葫芦画瓢直接在新建两个子仓库,分别起名child1_repo,child2_repo(名字随便起,自己认得就行)

    我们把主仓库(以下称parent)clone下来,随便提交点什么,像这样

    同样对子仓库child1_repo(以下简称child1)和child2_repo(以下简称child2)进行一样的操作。

    将子仓库添加至父仓库
    来到parent目录下,执行

    # []中为子仓库的git url
    git submodule add [child1 url]
    git submodule add [child2 url]
    1
    2
    3
    会出现如下提示:
    我们来看看这条命令做了哪些事情:

    首先,child1和child2被克隆到了parent目录下
    使用git status命令查看以下文件状态

    可以看到,除了两个子仓库外,还多了一个叫.gitmodules的文件,这是一份子模块与路径的映射关系图,git 根据这份文件去识别 submodule。现在查看一下文件内容:
    [submodule "child1_repo"]
    path = child1_repo
    url = git@github.com:xxx/child1_repo.git
    [submodule "child2_repo"]
    path = child2_repo
    url = git@github.com:xxx/child2_repo.git
    1
    2
    3
    4
    5
    6
    一个子仓库对应一个git url,清晰明了。

    提交
    我们将parent下的改动进行提交,并push到远程仓库上

    我们注意到,在commit了改动之后,除了常规的100644之外(100代表regular file,644代表文件权限),还出现了160000。

    160000 代表 Git 中的一种特殊模式,它本质上意味着你是将一次提交记作一项目录记录
    的,而非将它记录成一个子目录或者一个文件。
    上面这句话是什意思呢,我们通过git diff 查看刚才提交的信息

    # child1_repo
    Commit 8e182c74182adde49f2b6d192f2a85c50d87f538
    Commit Message add child1
    # child2_repo
    Commit 64a14d2c3f22aee584071b93c2bda4ef5243e4a2
    Commit Message add child2
    1
    2
    3
    4
    5
    6
    可以看到,这两个子仓库在parent下commit的就是一次提交的信息,而git就把它们当作是一个目录进行记录的。

    我们查看一下远端仓库的情况:

    可以看到,两个子仓库均已经push到了parent下,另外在child1和child2后面还跟着一串code,这是子仓库的commitId的后缀,表示该子仓库签出时的版本(这个在下面解释),这个code是不会显示在克隆到本地的仓库中的。

    进入child1_repo @ 8e182c7观察一下仓库的状态

    如图所示,此时child1处于一种游离的状态,在git页面无无法新建和编辑文件
    点击编辑会提示:

    you must be on a branch to make or propose changes to this file
    1
    我们点击上图画圈的部分,将其切换到master分支后,我们就可以执行正常的git操作。
    (注意:此时我们已经是在child1_repo下进行操作的)

    我们查看一下child1的commit记录

    可以看到,child1提交的commitId与parent中的child1_repo @ 8e182c7的后缀是一致的,因为本地parent子模块在push时签出的版本正是8e182c7

    总结一下,对于child1和child2来说,只有它们的远程 URL 会被记录在父仓库中,以及它们在主项目中的本地路径和签出的版本。

    模拟多人协作
    我们在git 页面尝试进入child1,其下有一个文件,我们尝试编辑这个文件,并将修改的内容提交,像这样

    再看看child1的commit记录,此时git head的指针已经指向了新的commitId:

    这是一个标准的git操作流程。

    我们返回到parent中查看一下child1的状态,并没有变化,记录依旧保持在第一次签出时的版本。

    拉取远程子模块的代码到本地
    子仓库在远程更改了,那么我们本地如何进行同步呢(如果只要修改主仓库的代码,正常的git操作就可以了)

    这里以child1为例,进入parent,执行

    git submodule update --remote child1_repo
    1
    这条命令将会拉取child1_repo中最新的提交,结果如下:

    这里,我们如果单纯的执行git submodule update,我们拉取的将是远程parent下最后一次签出的子仓库的版本。

    另外一种更新子仓库child1_repo的方法就是直接进入child1_repo目录下,像任何普通的Git那样进行操作即可。

    本地子模块修改提交到远程
    我们在本地的子模块中进行了一些修改,需要进行提交,如何操作呢?

    这里依旧以child1_repo为例进行阐述,在上述拉取child1最新的一次提交之后,我们本地相对于远端的parent已经有了改动,我们现在在本地再次进行一些修改,并进行提交。

    我们在本地cd到child1_repo目录中瞅瞅~


    首先,我们的修改是被捕捉到了,这说明我们是可以进行正常的git操作的。
    观察一下此时child1_repo的状态,它没有指向任何一个分支,而是停留在一个称作“游离的 HEAD”的状态,这意味着没有本地工作分支(例如 “master” )跟踪改动,你也就没办法提交代码。

    解决方案很简单,使用git checkout branch命令切换到某个分支就可以了
    我们把之前修改commit一下,然后切换到master分支上。


    我们尝试将本地子仓库的修改推送到远程(上述操作存在一个问题,导致我本地的修改丢失了,记得先pull,我这里重新修改提交了)

    我们切回到parent,使用 add commit push 三连将代码提交到远端(记得先pull),完事我们查看下远端的仓库

    看来已经正确的提交了:)

    可能会出现的幺蛾子
    Git对于子模块的管理相对来说比较复杂。当然出现异常的情况也是不可避免的,我们来看看在使用git submodule的过程中可能会出哪些问题。

    主模块提交并推送了改动,而子模块并没有推送
    如果我们在主仓库中提交并推送但并不推送子模块上的改动,其他人尝试更新子模块的人会遇到麻烦,因为他们无法得到依赖的子模块改动。那些改动只存在于我们本地的拷贝中。

    我们尝试一下上述过程,对child1_repo做一些修改并提交,但不推送。

    这里我又添加了一句话,并提交了。我们回到parent瞅瞅


    好,parent追踪到了submodule的改动,现在我们把它提交并推送到远程

    成功了…看来git并不会主动帮你检测子模块的改动是否推送。

    我们把本地的仓库删除,重新克隆一份下来。我们观察一下目录,所有子仓库只有一个空的文件夹,这里需要我们去git submodule init初始化本地配置文件以及 git submodule update 拉取代码。

    直接报错,无法更新了。

    为了确保这不会发生,你可以让 Git 在推送到主项目前检查所有子模块是否已推送。
    使用如下命令

    git push --recurse-submodules=check # 如果子模块没有提交,会直接报错
    # or
    git push --recurse-submodules=on-demand # 如果子模块没有提交,会尝试提交,提交不成功同时会阻止主仓库的推送
    1
    2
    3
    其他
    其实问题还不少,暂时不一一复现了,主要出现的问题参考了这篇博客
    另外还有别的可能出现的问题(e.g.将子目录转换成子模块、git submodule update failed等),可以参考文章结尾给出的文档

    在有子模块的项目中切换分支可能会造成麻烦
    如果你创建一个新分支,在其中添加一个子模块,之后切换到没有该子模块的分支上时,你仍然会有一个还未跟踪的子模块目录,这时候如果不小心提交了这个子模块(git commit -am “message”),就会有问题了。

    提交和获取的问题
    对子模块做了修改,需要先推送子模块再主模块,同时拉取的时候也需要先主模块,再子模块。

    记得先切换分支
    对子模块做本地修改需要先检出分支,否则有可能在 “游离的 HEAD” 上做修改。

    记得pull完了还得update一下
    如果你的同事更新了 submodule,然后更新了父项目中依赖的版本号。你需要在 git pull 之后,调用 git submodule update 来更新 submodule 信息。这儿的坑在于,如果你 git pull 之后,忘记了调用 git submodule update,那么你极有可能再次把旧的submodule 依赖信息提交上去(使用 git submit -am "message" 或者 git add .提交的人会遇到这种事)。

    参考
    git子模块
    git submodule(csdn)
    子模块 - Git Tower
    git submodule updated failed
    ————————————————
    版权声明:本文为CSDN博主「皇家茶壶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/breavo_raw/article/details/101857235

  • 相关阅读:
    2008秋季计算机软件基础点名册应用化学制药工程
    2008秋季计算机软件基础实验进程表应用化学制药工程
    格式化JavaScript代码
    MIME类型,MIME 参考
    2008秋季计算机软件基础0827课堂用例
    2008秋季解读大纲:计算机软件基础
    2008秋季计算机软件基础C语言精简课件
    2008秋季计算机软件基础应用化学制药工程授课日历
    几款JavaScript开发框架、开发库
    2008秋季计算机软件基础作业和实验报告注意事项
  • 原文地址:https://www.cnblogs.com/bigben0123/p/13213498.html
Copyright © 2011-2022 走看看