git submodule特点

Git submodule 从来不“跟随分支”,它只记录一个“精确的 commit”,像把子仓库钉死在某个时间切片上。

注意点:

  • 父仓库并不存子仓库的分支名。
  • 仓库只在 .gitmodules 里记录路径和 URL。
  • 真正决定子模块内容的是父仓库里记录的那个 commit SHA。

意味着你主仓库有:

  • master
  • dev
  • feature-x

每个分支都可以指向子仓库的不同 commit(哪怕都来自子仓库 master 分支)这完全没问题。


每个分支都对应子仓库的master 分支

1.固定版本模式

子仓库正常开发在 master。
父仓库某个分支只在需要升级时:

cd submodule
git checkout master
git pull
cd ..
git add submodule
git commit -m "bump submodule"

父仓库就记录了子仓库最新的那个 commit。

优点:
可控、可回滚、可审计。

缺点:
不是自动跟随。


2.自动跟随模式

.gitmodules 里加:

branch = master

然后:

git submodule update --remote

它会拉子仓库 master 最新 commit,并更新父仓库索引,但注意,父仓库仍然是记录具体 commit,不是记录“master”所以所谓“对应 master 分支”,只是通过 update –remote 达成的一种同步行为,而不是动态绑定。


submodule合并

假设:

  • 父仓库 master 分支记录子仓库 commit A
  • 父仓库 dev 分支记录子仓库 commit B

当你合并 dev -> master 时:

Git 看到的是:

子模块路径这个文件的 SHA 变了

它并不理解子仓库历史。

它只会判断:

  • 如果两个分支子模块指向不同 commit
  • 并且没有祖先关系

那就会产生冲突:

CONFLICT (submodule)

这时候需要你手动决定:

cd submodule
git checkout 想要的commit
cd ..
git add submodule
git commit

所以:
合并不会“出问题”,
但它不会自动替你做子仓库的 merge。

submodule 是“强一致引用机制”,不是“多仓库分支联动系统”。
它更像是:

父仓库记录一个外部依赖的精确版本

如果你希望多分支与子仓库分支强绑定、自动联动、自动 merge,那 submodule 不是理想工具。

架构层面理解submodule

graph TD
    A[Parent Repo - master] -->|records| C1[submodule commit A]
    B[Parent Repo - dev] -->|records| C2[submodule commit B]

    C1 --> S[Submodule Repo]
    C2 --> S

    note1[Parent stores commit SHA only]

重点是:
父仓库存的是 commit ID,不是 branch。

注意:很多大型项目后来都放弃了 submodule,因为跨分支协作时它非常容易制造“引用错位”。