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

Posted

技术标签:

【中文标题】Git tree-filter 在提交时运行 python 脚本【英文标题】:Git tree-filter run python script on commits 【发布时间】:2014-05-09 12:28:30 【问题描述】:

我之前在#git 上被问过这个问题,但由于它相当重要,我会在这里发布。我想在 repo 上运行 filter-branch 以使用 python 脚本在数百次提交中修改(数千个)文件。我在 repo 目录中使用以下命令调用 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 没有完成修复提交。 似乎存在权限问题,但我无法获得在它周围以提升的权限运行。我已经尝试使用 git v1.8 和 v1.9 在 win7、win8 和 ubuntu 上运行过滤器分支。编辑该脚本在 Centros 上与 git1.7.1 一样工作 p>

目标是在files/*/*/** 中的内容与数据库同步后减小 CDN 存储库的大小(接近 1GB)。The source code of the projectTarget repo for the rewrite

【问题讨论】:

git --version 的输出是什么? 您能澄清一下您要清理的存储库是什么吗?是github.com/jsdelivr/jsdelivr(当前包大小~284MB)吗? @michas 我试过在v1.9.0v1.8.51.8.3 上运行它。是的,这是正确的回购罗伯托 【参考方案1】:

您遇到的权限问题很有趣——您是在存储库的本地副本(即您可以完全访问文件系统的地方)还是在远程服务器上执行此操作?

阅读您的 python 代码,您似乎正在尝试删除每个大小超过一定大小的文件,而不是 .INI 文件,我没听错吗?

如果是这样,请问您是否考虑过The BFG Repo-Cleaner?显然,您可以通过编写自己的代码(我知道我有)学到很多关于 Git 的知识,但我认为 BFG 可能是为您的需求量身定制的 - 并且会比任何基于 git-filter-branch 的方法更快。

在您的情况下,您可能希望使用如下命令运行它:

$ java -jar bfg.jar --strip-blobs-bigger-than 100K  my-repo.git

这会删除所有大于 100K、不在您最新提交中的 blob。

我在jsdelivr repo 上快速运行了这个,并在the cleaned repo 中将包大小从 284M 减少到 138M。 BFG 清理步骤耗时不到 5 秒,随后的 git gc --prune=now --aggressive 不到 2 分钟。

全面披露:我是 BFG Repo-Cleaner 的作者。

【讨论】:

此外,我们当前的文件也不是神圣的 - 有没有让您的工具命中所有提交到 HEAD 再神圣:--no-blob-protection 是你(可怕的)朋友! 好吧整洁 - 看起来很有希望。无论如何要指定***REMOVED*** 文本,您的项目是否支持全局路径? 谢谢,上下文很好!将 BFG 更改为零文件 (github.com/rtyley/bfg-repo-cleaner/blob/ed21bed/bfg-library/src/… ) 并不难,但从阅读问题 347 来看,我认为这对您尝试做的事情的精神并不重要 - 替换文件称为“文件名”我认为 .REMOVED.git-id' 会很好。总的来说,我不确定 /frequent/ 历史重写是否对 jsdelivr 项目有好处 - 是否会让提交拉取请求的人感到困惑? 关于字节大小 - 我刚刚削减了 BFG 的 v1.11.3 版本,支持按单字节文件大小过滤文件!几小时内将在repo1.maven.org/maven2/com/madgag/bfg 上显示。【参考方案2】:

您不应将cd 转移到另一个目录,因为git-filter-branch script 将使用相对路径来访问文件。

【讨论】:

脚本在其相对目录中加载一些.yml 文件,过滤器分支在repos 路径的上下文中执行命令。 AFAIK 无法设置 cwd 路径【参考方案3】:

考虑使用BFG。它使用起来更快更简单。

【讨论】:

以上是关于Git tree-filter 在提交时运行 python 脚本的主要内容,如果未能解决你的问题,请参考以下文章

我可以使用 Git 以两种方式更改提交历史记录吗?

git提交大文件无法推送到远程库

为修改后的更改的每次提交运行 pylint

如何在运行 Azure 管道时使用标记在提交时获取 git 分支?

git的推送忽略

git的推送忽略