经常会在做一个项目时,随着功能的增加,项目的源代码越来越庞大,在某一天,终于受不了,决定要拆分代码到多个独立的模块。
这时候,如果你是用git来管理源代码,事情就简单多了,使用git的filter-branch工具,可以快速的把子目录分离为一个独立库,而且还能保留修改历史。
当然,使用svn或者其他代码仓库的,也不要灰心,可以先转换为git库再处理,
git的filter-branch有一个index-filter,可以让你按任意策略重新定义整个源代码目录树结构和文件内容。git手册中的例子是删除所有提交的某一个文件,只能算是index-filter的牛刀小试,这里要完成的任务才能基本体现index-filter的强大。
比如,有这样一个目录结构:
/
- include
- module-A
- module-B
- src
- module-A
- module-B
根目录下有include、src、make三个子目录,分别用于存放头文件、实现文件,这是一个比较典型目录结构,每个子目录下又按模块划分了很多子目录。现在目标是将模块独立,形成下面的目录结构,(模块A、B都是这样的结构):
/
- include
- src
别忘了,这个项目还有好几个分支,比如branch-1、branch-2。看起来事情蛮复杂的,需要好好规划一下。
首先按照每个模块、每个分支建立对应分支,如:module-A/branch-1、module-A/branch-2、module-B/branch-1 module-B/branch-2,建立的分支与一开始原先的分支位于同一个提交(commit)上。
然后,通过index-filter修改目录结构。
用module-A/branch-1为例,需要将 include/module-A移动到 include目录,将 src/module-A移动到 src目录,所以index-filter的脚步应该这样写:
filter.sh:
#!/bin/bash
git read-tree --empty
git read-tree --prefix=/include ${GIT_COMMIT}:include/module-A
git read-tree --prefix=/src ${GIT_COMMIT}:src/module-A
调用index-filter的命令行为:
git filter-branch -f --index-filter filter.sh module-A/branch-1
filter.sh需要可执行权限。
应为原先git库的每次修改一般只针对一个模块,所以通过index-filter处理后,新的分支上有很多提交是空的,也就是没有修改代码。这时候,可以通过commit-filter删除空提交,命令为:
git filter-branch -f --commit-filter 'git_commit_non_empty_tree "$@"' module-A/branch-1
好了,一个分支处理完了,剩下的三个分支类似处理。
这样,对应于module-A,有module-A/branch-1、module-A/branch-2,我们需要将这两个分支分离到独立的库中,可以这样做:
git init --bare ../module-A.git
git push ../module-A.git refs/heads/module-A/*:refs/heads/*
最后从module-A.git中克隆出来,就是module-A独立的代码了。
git clone module-A.git