在提交上运行 python 脚本的 Git tree-filter
我之前在#git
上被问到这个问题,觉得内容比较多,所以在这里分享一下。我想在一个代码库上运行filter-branch
,用一个Python脚本来修改成千上万的文件,涉及到好几百次提交。我在代码库目录下用以下命令调用clean.py
脚本:
git filter-branch -f --tree-filter '(cd ../cleaner/ && python clean.py --path=files/*/*/**)'
Clean.py脚本的内容是这样的,它会修改路径下的所有文件(也就是files/*/*/**
):
from os import environ as environment
import argparse, yaml
import logging
from cleaner import Cleaner
parser = argparse.ArgumentParser()
parser.add_argument("--path", help="path to run cleaner on", type=str)
args = parser.parse_args()
# logging.basicConfig(level=logging.DEBUG)
with open("config.yml") as sets:
config = yaml.load(sets)
path = args.path
if not path:
path = config["cleaner"]["general_pattern"]
cleaner = Cleaner(config["cleaner"])
print "Cleaning path: " + str(path)
cleaner.clean(path, True)
运行命令后,终端输出了以下内容:
$ python deploy.py --verbose
INFO:root:Checked out master branch
INFO:root:Running command:
'git filter-branch -f --tree-filter '(cd C:/Users/Graeme/Documents/programming/clean-cdn/clean-jsdelivr/ && python clean.py --path=files/*/*/**)' -d "../tmp"' in ../jsdelivr
Rewrite 298ec3a2ca5877a25ebd40aeb815d7b5a5f33a7e (1/1535)
Cleaning path: files/*/*/**
C:\Program Files (x86)\git/libexec/git-core\git-filter-branch: line 343: ../commit: No such file or directory
C:\Program Files (x86)\git/libexec/git-core\git-filter-branch: line 346: ../map/298ec3a2ca5877a25ebd40aeb815d7b5a5f33a7e
: No such file or directory
could not write rewritten commit
rm: cannot remove `/c/Users/Graeme/Documents/programming/clean-cdn/tmp/revs': Permission denied
rm: cannot remove directory `/c/Users/Graeme/Documents/programming/clean-cdn/tmp': Directory not empty
这个Python脚本执行得很成功,文件也修改得很正确,但filter-branch
没有完成提交的修复。看起来是权限问题,不过我尝试以更高权限运行也没能解决。我在win7、win8和ubuntu上都试过,使用的是git v1.8和v1.9版本。
补充 这个脚本在CentOS上用git1.7.1
运行得很好。
我的目标是减少一个接近1GB的CDN代码库的大小,等到files/*/*/**
里的内容和数据库同步完成后。
项目的源代码
重写的目标代码库
3 个回答
可以考虑使用 BFG。这个工具用起来更快,也更简单。
你不应该使用 cd
命令去切换到其他目录,因为 git-filter-branch
脚本 会用相对路径来访问文件。
你遇到的权限问题挺有意思的——你是在本地的代码库上操作吗(也就是说,你对文件系统有完全的访问权限),还是在远程服务器上?
看你写的Python代码,似乎是想删除所有超过一定大小的文件,前提是这些文件不是以.INI结尾的,对吧?
如果是这样的话,我想问问你有没有考虑过BFG Repo-Cleaner?显然,自己写代码能学到很多关于Git的知识(我也是这样),但我觉得BFG可能更适合你的需求,而且它的速度比用git-filter-branch
的方法要快。
在你的情况下,你可以用类似下面的命令来运行它:
$ java -jar bfg.jar --strip-blobs-bigger-than 100K my-repo.git
这个命令会删除所有大于100K的文件,这些文件不在你最新的提交中。
我在jsdelivr这个代码库上快速试了一下,结果把包的大小从284M减少到了138M,清理的过程不到5秒,后面的git gc --prune=now --aggressive
大约花了2分钟。
完全透明:我是BFG Repo-Cleaner的作者。