- Published on
Git拆分子目录为新仓库
- Authors
- Name
- ttyS3
en title: Git Splitting a Subfolder Out Into a New Repository
需求
某个历史悠久的“大”Git仓库(很大很大。。。)要拆分成很多小仓库。
至于为什么会有这种“大”仓库的存在,表问我。。。 it's about project history
为什么要这样做?
- 查bug的时候不再需要同时切换新旧两个仓库交叉查看历史commit记录
- 可以保留被拆分目录下文件的完整提交记录,方便他人阅读代码和理解代码
这样做会不会增加迁移的负担?
不会,绝对不会。一条命令即可搞定 (git filter-repo xxxxx)。
准备工作
git-filter-repo
现在是Git官方推荐的工具(git自带的filter-branch
已经不被推荐使用了,速度慢又不好用)。
git filter-repo is now recommended by the git project instead of git filter-branch. https://git-scm.com/docs/git-filter-branch#_warning
注: github 官方文档里也有个拆分子目录的教程,那个是用的
filter-branch
, 已经过时了,不用看了。
安装filter-repo
安装git-filter-repo
只需要执行一次:
pip3的模块带的可执行文件默认情况下会安装到 $HOME/.local/bin
, 因此要把$HOME/.local/bin
加入PATH
环境变量。
如果你的系统有不同的配置,以你自己的系统为准,比如Mac之类的, 如果偏爱brew, 可以参考官方文档 https://github.com/newren/git-filter-repo/blob/main/INSTALL.md
#安装 filter-repo
pip3 install --user git-filter-repo
# 将以下环境变量配置放到你自己正在使用的shell的rc配置文件中(如.bashrc, .zshrc 等)
export PATH="$HOME/.local/bin:$PATH"
大仓库准备(只需要执行一次):
大仓库作为历史仓库,需要拆分成很多小仓库,原则上我们不会再添加新代码了。
首先,我们将大仓库THE_BIG_REPO
clone一份,保存为THE_BIG_REPO.orig
, 避免以后每次要从github clone,速度太慢。
这里 ~/repo/go/split-work
是我用于迁移专门准备的目录。
~/repo/go/split-work
❯ cd ~/repo/go/split-work
❯ git clone git@github.com:VendorName/THE_BIG_REPO.git THE_BIG_REPO.orig
THE_BIG_REPO.orig
作为拆分的原始仓库, 其它拆分每次从这个目录clone
迁移步骤
1.拆分子目录为仓库
以 xxx_write_agent 这个子目录(实际上它是一个单独的微服务)为例。
~/repo/go/split-work
是我用于迁移专门准备的目录。
cd ~/repo/go/split-work/
# 将我们之前clone好的大仓库,clone一份到当前目录,为方便识别,重命名目录为 xxx_write_agent
git clone ~/repo/go/split-work/THE_BIG_REPO.orig xxx_write_agent
# 进入 xxx_write_agent
cd xxx_write_agent/
# 20200723 修正:git checkout xxx 不能执行,执行后会提示 Refusing to overwrite repo history since this does not look like a fresh clone.
# 好了,关键的操作来了
# 现在我们所在的 xxx_write_agent 目录,实际上是整个老仓库
# 假设我们要迁移的 xxx_write_agent 目录相对于当前目录的路径是: a-parent-path/project/another-pkg/xxx_write_agent
# 执行以下命令,将自动干掉其它目录,只保留 xxx_write_agent 目录及其commit记录
git filter-repo --subdirectory-filter a-parent-path/project/another-pkg/xxx_write_agent
好了,现在的 xxx_write_agent 仓库已经是名副其实的 xxx_write_agent 了。
接下来我们要做一些清理工作
2.清理工作
清理除 dev
之外的其它branch
由于在老仓库,我们的 dev
是最新的分支,因此,我们只需要保留 dev
分支即可。其它branch和tags 如果推送到了新仓库,会带来干扰。
值得高兴的是, 之前的仓库没有发过任何版本,也不存在任何tag, 因此我们可以省掉清tag这一步了。只需要清除branch。
如果你的情况不同,请按你自己的来,比如,你的仓库很可能是 master 是最新的。
以下命令中
git br
是一个git别名, 有人可能配置成了shell的别名,比如gbr
, 如果没有的,请自行把它换成原版的完整命令git branch
git checkout dev && git br | grep -v '*' | xargs -I'{}' git br -D '{}'
将原dev(最新分支)重命名为 develop
(主要是用于git flow)
git br -m dev develop
在dev的基础上创建 master 分支 (主要是用于git flow, 初始化时必须有master分支):
git br master
初始化 git flow
:
(注, 我这里用了默认配置,这个是我在全局.gitconfig
中已经配置好了,请参见末尾"git flow 相关配置")
❯ git flow init -d
Using default branch names.
Which branch should be used for bringing forth production releases?
- develop
- master
Branch name for production releases: [master]
Which branch should be used for integration of the "next release"?
- develop
Branch name for "next release" development: [develop]
Hooks and filters directory? [/home/ttys3/repo/go/split-work/split/THE_BIG_REPO/.git/hooks]
给原始代码新建一 0.0.1
版本,记录一下这是原始迁移过来的代码。后续的发版都是从 0.1.0
开始,因此可以很好的区分哪些是历史commit.
git flow release start 0.0.1 && git flow release finish '0.0.1'
message内容为:
split subdir to repo from github.com/VendorName/THE_BIG_REPO dev branch
好了,到这里,拆分并保留commit记录的任务已经完成了。
其实核心的命令只有一条:
git filter-repo --subdirectory-filter 需要保留的子目录的相对路径
git flow 相关配置
编辑全局.gitconfig
配置文件,增加git flow 相关配置:
[gitflow "prefix"]
feature = feature/
bugfix = bugfix/
release = release/
hotfix = hotfix/
support = support/
versiontag = v