git submodule

  • git submodule

  • gitsubmodule有关的信息保存在两个地方:

    • .gitmodules在仓库中,有版本控制,修改之后会同步到其他仓库,使用submodule相关命令的时候会自动更新
    • .git/config在本地,需要手动更新,或者执行git submodule sync将新的配置从.gitmodules拷贝到.git/config
    • git submodule sync会将submodule远程的 url 配置设置到.gitmodules,并且只会影响.git/config已经有 url 的条目
    • 指定--recursive,将会递归更新注册的submodule

应用场景

  • 场景1:添加一个submodule
    • git submodule add repo_url local_path
    • 此命令做三件事:克隆工程到本地;创建/修改.gitmodules标记submodule的具体信息;更新.git/config文件,增加submodule的地址
    • 可用git submodule add -b branch_name repo_url local_path指定submodule跟踪的分支
  • 场景 2:删除一个submodule
    • git submodule deinit -f -- path_to_submodule(路径最后不要加斜线)
    • 删除.git/modules下面的文件夹
    • 从 git 版本控制中删除缓存的子模块对应文件夹
    • 本地仍保留文件git rm --cached path_to_submodule(路径最后不要加斜线)
    • 本地不保留文件git rm -f path_to_submodule(路径最后不要加斜线)
  • 场景 3:更新submoduleurl
    • 删除.git/config相关代码
    • 删除工程目录下的.gitmodules相关代码
    • 执行git submodule sync --recursive更新到本地的配置文件
  • 场景 4:克隆一个有submodule的项目
    • 分步克隆
    • git clone repo_urlsubmodule的代码不会和父项目一起克隆出来
    • git submodule update --init [--recursive]可以检出submodule的代码,recursive适用于嵌套submodule的项目
    • git submodule update --init [--recursive] subname可以检出指定子模块subname的代码,recursive适用于嵌套submodule的项目
    • 一步克隆
    • git clone repo_url --recursive
  • 场景 5:更新submodule,与远程仓库同步

    • 更改对应的submodule提交到远程仓库
    • 在父工程中,进入该submodule,执行git pull,可以用git status查看submodule是否有改到
    • 如果有改到,需要执行git add提交该submodule的更新
    • 也可在父工程中执行git submodule update --remote更新所有子模块到最新版本,再执行git add提交所有子模块的更新
    • 注意:在含有子模块的工程中,每次执行git pull之后需要执行git submodule update --remote更新子模块
    • 技巧:可以通过修改~/.gitconfig设置每次git pull之后执行git submodule update --remote

      [alias]
      psu = !git pull && git submodule update
      

问题

  • 问题 1:git submodule add时报错A git directory for xxx is found locally with remote(s): origin
    • 删除.git/config相关代码
    • 删除工程目录下的.gitmodules相关代码
    • 删除缓存的子模块git rm --cached path_to_submodule`(路径最后不要加斜线)
    • 执行git submodule sync --recursive更新到本地的配置文件
  • 问题 2:git submodule add时报错Pathspec xxx is in submodule
    • 删除缓存的子模块git rm --cached path_to_submodule(路径最后不要加斜线)

高级命令

  • 查看差异输出,使得子模块的差异输出更加具体git diff --cached --submodule
  • 修改子模块跟踪分支
    • 只修改本地:修改.git/config文件中对应子模块的设置
    • 修改仓库:
    • 修改.gitmodule的命令git config -f .gitmodules submodule.Utility.branch dev
      • Utility是子模块的名字
      • devUtility的分支
      • 不用-f .gitmodules只会应用到本地
    • 同步到本地配置git submodule sync????
  • 在主项目查看子模块的更改摘要:配置选项status.submodulesummary,使用命令git config status.submodulesummary 1
  • 子模块遍历
    • 遍历子模块保存工作进度git submodule foreach 'git stash save'
    • 遍历子模块新建工作分支git submodule foreach 'git checkout -b featureA'
    • 在主项目查看所有子模块的修改内容git diff; git submodule foreach 'git diff'
    • 删除所有子模块本地的修改git submodule foreach --recursive 'git checkout .'
  • 在主项目修改子模块
    • git submodule update更新子模块的文件时,会将子仓库留在一个游离的HEAD状态,本地没有工作分支跟踪改到
    • 首先进入子模块检出一个分支,修改之后提交到本地
    • 拉取远程仓库的子模块提交并合并到本地git submodule update --remote --rebase/merge
  • 发布子模块的改到
    • 在主项目推送代码到远程仓库前检查本地有没有未推送的子模块修改git push --recursive-submodules=check
    • 如果提交的子模块改到未推送,会导致主项目的推送失败,可以根据提示进入子模块然后推送到远程仓库
    • 或者使用git push --recursive-submodules=on-demandgit会尝试推送子模块修改到远程仓库,只有子模块都推送成功,主项目才可以推送

相关