第9章:邪恶的submodule

基础知识

在worktree内部创建新的repo/worktree是坏的,因为一个文件受两个repo管辖。 一个workaround是将这个小的repo/worktree变成大repo的一个submodule。

一个submodule的信息可以分为静态与动态两大部分,总共分散在5个位置:

  • .gitmodules文件中包含一部分静态信息:

    • submodule (name):名字

    • path:应该放在worktree的哪个路径里面

    • url:在哪里能够找到包含该commit的repo

    • branch:没有什么卵用

    • update:如何处理下级repo的更改

  • index中包含另一部分静态信息:

    • commit:上级repo期待哪个commit

  • .git/config文件中包含一部分动态信息:

    • submodule (name)

    • active:启用/禁用

    • url

    • update

  • .git/modules/<name>/是下级repo,包含一部分动态信息

  • <path>是下级repo的worktree,包含一部分动态信息

添加/更新submodule的静态部分(.gitmodules/index)

非常简单,直接修改.gitmodules和index:

  • Lv1

  • Lv2

非常遗憾的是,没有Lv3的方法能够做到这一点。

.gitmodules来更新.git/config

  • Lv2

  • Lv3

.git/config和index来更新repo和worktree

git submodule update是实现这个功能的Lv3命令。 其基本语法是 git submodule update [--checkout|--rebase|--merge] -- <path> 若未指定那三个选项,其功能根据git config submodule.<name>.update而定,共有5种:

  • checkout(此为默认情况)

  • rebase

  • merge

  • none

  • !...

下面将分别介绍。

git submodule update --checkout == git clone

  • Lv2

由于其中有git fetch,巨量无关数据一并被下载了下来。

  • Lv3

这里面依然有git fetch。 为了解决这个问题,可以使用git-get

git submodule update --checkout [-f] == git switch [-f] <commit>

假设index发生了变动:

  • Lv2

  • Lv3

git submodule update --rebase == git rebase <commit>

(先回到原来的HEAD位置)

假设repo中HEAD发生了变动:

然后index又发生了变动:

现在希望能够把下级repo中新的改动rebase到e973上:

  • Lv2

  • Lv3

git submodule update --merge == git merge <commit>

(先回到原来的HEAD位置)

假设repo中HEAD发生了变动:

然后index又发生了变动:

现在希望能够在下级repo中merge上级以为的新的改动:

  • Lv2

  • Lv3

其他两种git config submodule.<name>.update

.gitmodules和index来创建repo和worktree

分两步:用.gitmodules来更新.git/config;再用.git/config和index来更新repo和worktree。 Lv2不再赘述。

  • Lv3

用repo来更新index

(先回到原来的HEAD位置)

假设repo中HEAD发生了变动:

现在希望index也跟着变动:

  • Lv1

  • Lv2

  • Lv3

.gitmodules来更新.git/config和repo的URL

  • Lv2

  • Lv3

一次性添加.gitmodules.git/config、index、repo、worktree

  • Lv2

先添加.gitmodules和index,然后用.gitmodules更新.git/config, 然后用.git/config和index创建repo和worktree。

  • Lv3

注意:只能指定一个branch,不能指定某个commit。 包括git fetch,可能造成大量资源浪费。

删除.git/config和worktree

  • Lv2

  • Lv3

删除.gitmodules和index

  • Lv2

  • Lv3

非常遗憾的是,repo必须手工rm -rf

由repo和worktree创建.gitmodules和index

假设如此创建repo和worktree:

现在欲将parent/whatever/path纳入parent当成submodule管理。

  • Lv2

  • Lv3

总结

  • 一次性添加submodule的五个部分:

    • git submodule add [-b <branch>] [--name <name>] -- <url> <path>

  • 分别修改submodule的五个部分:

    • .gitmodules

      • Lv0: vim .gitmodules

      • Lv2: git config --file=.gitmodules submodule.<name>.<key> <value>

    • $GIT_DIR/config

      • Lv0: vim .git/config

      • Lv2: git config submodule.<name>.<key> <value>

    • index

      • Lv2:git update-index [--add|--force-remove] --cacheinfo 160000,<sha1>,<path>

    • repo ($GIT_DIR/modules/<name>)

      • git -C <path> ...

    • worktree ($GIT_WORK_TREE/<path>)

      • git -C <path> ...

  • 用静态更新动态:

    • git submodule init -- <path>

      • .gitmodules来更新.git/config

    • git submodule update --init [--recursive] --checkout -- <path>

      • .gitmodules和index来创建repo和worktree

    • git submodule sync -- <path>

      • .gitmodules来更新.git/config和repo的URL

    • git gets -- <path>

      • 快速下载指定commit

  • 用静态和动态更新动态:

    • git submodule update [--recursive] [--checkout|--rebase|--merge] -- <path>

      • .git/config和index来更新repo和worktree,共5种选项

  • 用动态更新静态:

    • git update-index -- <path> - 用repo来更新index

    • git add <path> - 用repo来更新index

    • git submodule absorbgitdirs -- <path>

      • 有repo、worktree、.gitmodules和index之后,用该命令创建.git/config并将repo移动到正确位置

  • 删除:

    • git submodule deinit -f -- <path>

      • 删除.git/config和worktree

    • 其他部分需要逐一删除

最后更新于

这有帮助吗?