HOME AUTHORS

从当前仓库中分离出子目录作为submodule或者subtree

2019年8月4日 20:40
owl
Tags clone filter submodule subtree 仓库

博客使用简单的Django框架,一直使用git管理整个项目的开发。 基于这个前提,如何保留尽量多的信息,将博客部分开源独立出去,独占一个仓库?

我验证了几种容易找到的方案,最终还是选择使用subtree管理博客部分。 以下实验均在同一目录下进行,使用拉丁字母命名实验用的新仓库,每个仓库均 直接 clone自原仓库(c除外)。 最好使用clone来的新仓库,防止因原仓库有未追踪的文件而出现冲突,意外中止某些关键操作 “最好”的语气需要强烈,既然有着重提示,那么背后一定有部血泪史。

submodule

[a]使用subtree分割,添加submodule

以下实验验证用subtree分割出新的分支,并将分支提交到远程仓库,最后将远程仓库作为submodule添加回本仓库。

# 初始化远程仓库
git init --bare /tmp/blog_a.git
git remote add blog_a /tmp/blog_a.git

# 分割出子目录blog并创建为blog分支
git subtree split -P blog -b blog
git push blog_a blog:master

# 先删除目录才能添加submodule
git rm -r blog
git submodule add /tmp/blog_a.git blog
git commit

[b]直接添加submodule

以下实验验证可以在直接clone自原仓库的实验仓库b中添加实验仓库a分离出来的部分作为submodule

git rm -r blog
git submodule add /tmp/blog_a.git blog

[c]如何clone带有submodule的仓库并使用submodule

以下实验练习clone和使用带有submodule的仓库。

git clone b c
git submodule init
git submodule update

subtree

[d]使用subtree分割,直接使用subtree

以下实验验证直接使用subtree的功能,不使用submodule

git init --bare /tmp/blog_d.git
git remote add blog_d /tmp/blog_d.git

# 以下有两种方案

# 创建blog分支并合并入当前分支(--rejoin选项)
git subtree split -P blog --rejoin -b blog
git push blog_d blog:master

# 基本同样的操作,但是不会创建blog分支
git subtree push -P blog blog_d master

--rejoin可以自己通过在master等原仓库分支使用git merge blog --allow-unrelated-histories实现。

[e]使用filter-branch分割(修改分支)

以下参考github上一篇帮助,使用重量级武器filter-branch分割仓库。

https://help.github.com/en/articles/splitting-a-subfolder-out-into-a-new-repository

git checkout -b blog
git filter-branch --prune-empty --subdirectory-filter blog blog

# 查看git log,会有一个如下的残留引用
# refs/original/refs/heads/blog
# 这个好像无法避免

git init --bare /tmp/blog_e.git
git remote add blog_e /tmp/blog_e.git

git push -u blog_e master

此方法和使用subtree(不带--rejoin)一样的效果,一样的日志,可以直接使用subtree分离出来的仓库作为远程仓库同步。

总结

从以上参考的方法来看,分割方法主要为两种,使用subtreesplit或者使用filter-branch,两种方法无效果上的差别 (我猜subtreesplit就是用filter-branch实现的,以后验证)。

使用subtree或者submodule管理分割出来的分支就是比较灵活的事,二者使用上就见仁见智吧。