在提交上运行 python 脚本的 Git tree-filter

4 投票
3 回答
1519 浏览
提问于 2025-04-18 00:31

我之前在#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 个回答

0

可以考虑使用 BFG。这个工具用起来更快,也更简单。

1

你不应该使用 cd 命令去切换到其他目录,因为 git-filter-branch 脚本 会用相对路径来访问文件。

2

你遇到的权限问题挺有意思的——你是在本地的代码库上操作吗(也就是说,你对文件系统有完全的访问权限),还是在远程服务器上?

看你写的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的作者。

撰写回答