35.4 Git版本库整理
Git提供了太多武器进行版本库的整理,可以将一个Git版本库改头换面成另外一个Git版本库。
使用交互式变基操作,将多个提交合并为一个(参见第2篇第12章“12.3.3时间旅行三”小节)。
使用StGit,合并提交及更改提交(参见第3篇第20章"20.3.1 StGit"小节)。
借助变基操作,抛弃部分历史提交(参见第2篇第12章“12.4丢弃历史”小节)。
使用子树合并,将多个版本库整合在一起(参见第4篇“第24章 子树合并”)。
使用git-subtree插件,将版本库的一个目录拆分出来成为独立版本库的根目录(参见第4篇第24章"24.5.4 git subtree split"小节)。
但是有些版本库重整工作如果使用上面的工具会非常困难,而采用另外一个还没有被用到的Git命令git filter-branch却可以做到事半功倍。看看使用这个新工具来实现下面的这几个任务是多么的简单和优美。
(1)将版本库中某个文件彻底删除[1]。即凡是有该文件的提交都逐一做出修改,撤出该文件。
$git filter-branch—tree-filter 'rm-f filename'——all
(2)更改历史提交中某一提交者的姓名及邮件地址。
$gitfilter-branch—commit-filter'
if["$GIT_AUTHOR_NAME"="Xin Jiang"];then
GIT_AUTHOR_NAME="Jiang Xin"
GIT_AUTHOR_EMAIL="jiangxin@ossxp.com"
GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
f
git commit-tree "$@";
'HEAD
(3)为没有包含签名的历史提交添加签名。
$git filter-branch-f—msg-filter'
signed=false
while read line;do
if echo$line|grep-q Signed-off-by;then
signed=true
f
echo$line
done
if!$signed;then
echo""
echo "Signed-off-by:YourName<your@email.address>"
f
'HEAD
通过上面的例子,可以看出命令git filter-branch针对不同的过滤器提供可执行脚本,从不同的角度对Git版本库进行重构。该命令的用法如下:
git filter-branch[—env-filter<command>][—tree-filter<command>]
[—index-filter<command>][—parent-filter<command>]
[—msg-filter<command>][—commit-filter<command>]
[—tag-name-filter<command>][—subdirectory-filter<directory>]
[—prune-empty]
[—original<namespace>][-d<directory>][-f|—force]
[—][<rev-list options>…]
这条命令异常复杂,但是大部分参数是用于提供不同接口的,因此还是比较好理解的。
该命令最后的<rev-list>参数提供要修改的版本范围,如果省略则相当于HEAD指向的当前分支。也可以使用—all来指代所有引用,但是要在—all和前面的参数间使用分隔符“—”。
运行git filter-branch命令改写分支之后,被改写的分支会在refs/original中对原始引用做备份。对于在refs/original中已有备份的,该命令拒绝执行,除非使用-f或—force参数。
其他的后面可带命令脚本<command>的参数(如—env-filter<command>),为git filter-branch命令提供相应的编程接口,从不同的角度实现对Git版本库的过滤。下面针对各个过滤器分别进行介绍。
35.4.1 环境变量过滤器
参数—env-filter用于设置一个环境变量过滤器。该过滤器用于修改环境变量,对特定的环境变量的修改会改变提交。下面的示例可用于修改作者/提交者的邮件地址[2]。
$git filter-branch—env-filter'
an=" $GIT_AUTHOR_NAME"
am=" $GIT_AUTHOR_EMAIL"
cn=" $GIT_COMMITTER_NAME"
cm=" $GIT_COMMITTER_EMAIL"
if[" $cn"="Kanwei Li"];then
cm=" kanwei@gmail.com"
f
if["$an"="Kanwei Li"];then
am="kanwei@gmail.com"
f
export GIT_AUTHOR_EMAIL=$am
export GIT_COMMITTER_EMAIL=$cm
'
这个示例和本节一开始介绍的更改作者/提交者信息的示例功能相同,但是使用了不同的过滤器,你可以根据喜好自由选择。
[1]这里使用的命令并非最优实现,后面会介绍一个运行得更快的命令。