CRCMS

高山仰止,景行行止,虽不能至,心向往之

大道至简


通过git subtree来创建自己的子仓库

简述

查看laravel/framework,就会发现其实laravel主包是由多个子包构建。
每个子包又都可以独立使用,主包中相关子包的commit必须一致,同时还需要同步更新方便。如何做到这一点的呢?

Subtree

subtree 是什么

git subtree 可以实现一个仓库作为其他仓库的子仓库。或者说,可以实现一个主仓库包含多个子仓库。

subtree 的使用

查看git subtree --help,发现命令如下:

1
2
3
4
5
6
git subtree add   -P <prefix> <commit>
git subtree add -P <prefix> <repository> <ref>
git subtree pull -P <prefix> <repository> <ref>
git subtree push -P <prefix> <repository> <ref>
git subtree merge -P <prefix> <commit>
git subtree split -P <prefix> [OPTIONS] [<commit>]

测试

使用以下简写来代表仓库名称:

  • A:主仓库
  • B:子仓库
  1. 首先新建一个A仓库,进入A的主目录,在A仓库中执行命令(假定所有子仓库目录都存在于A/src中)
    1
    git subtree add -P src/B https://github.com/B.git master

此时subtree则在A仓库中绑定了B仓库

  1. 进入A/src/B

    1
    touch test
  2. A根目录提交commit

    1
    2
    3
    git add src/B/test
    git commit -m "subtree test"
    git push origin master

那是如何同步相关commit到子仓库呢?subtree push即可

1
git subtree push -P src/B https://github.com/B.git master

即此,已经完成A,B仓库相关commit同步

优化

如果,A/src中有很多子仓库,每次更新完成后,手动更新N个子仓库非常让人头疼,索性搞个Bash跑一遍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env bash
set -euo pipefail

TARGET_DIRECTORY="$(pwd)/src"

function git.branch {
br=`git branch | grep "*"`
echo ${br/* /}
}
BRANCH=$(git.branch)

# each所有目录
for file in `ls ${TARGET_DIRECTORY}`
do
if [[ -d "${TARGET_DIRECTORY}/${file}" ]]; then
echo -e "==================Current:${file}==================\n"
echo `git subtree push -P src/${file} git@github.com:${file}.git ${BRANCH}`
echo -e "\n"
fi
done

Composer replace

可以看到在laravel/composer.json中有replace属性

1
2
3
4
5
6
"replace": {
"illuminate/auth": "self.version",
"illuminate/broadcasting": "self.version",
"illuminate/bus": "self.version"
......
}

那么如果是PHP情况下我们也可以,使用replace来在主包中加载子包依赖,从而提升统一版本更新的便捷性。

相关资料

Composer Replace使用
Git subtree使用