2

我的 repo 是从一个开源项目中派生出来的,所以我不想在 ForkPoint 标记之前修改提交。我已经尝试过BFG Repo Cleaner,但它不允许我指定范围。

我想要

  1. 穿越历史ForkPoint..HEAD^
  2. 重写提交以删除所有大于 10M 的文件

如何从 git 存储库中删除未使用的对象?说应该是这样的

BADFILES=$(find . -type f -size +10M -exec echo -n "'{}' " \;)
git filter-branch --index-filter \
"git rm -rf --cached --ignore-unmatch $BADFILES" ForkPoint..HEAD^

BADFILES不仅包含存在于HEAD?

例如,如果我错误地提交了一个HUGE_FILE然后又提交了另一个删除该文件的提交,则BADFILES搜索将找不到,HUGE_FILE因为find在当前工作树中看不到它。


Edit1:现在我正在考虑在克隆上使用 BFG,然后将我的叉子移到原始的 ForkPoint 上。fatRepo这会是正确的命令slimRepo吗?

mkdir merger ; cd merger ; git init
git remote add fat  ../fatRepo
git remote add slim ../slimRepo
git fetch --all
git checkout fat/ForkPoint
git cherry-pick slim/ForkPoint..slim/branchHead

Edit2:樱桃采摘不起作用,因为樱桃采摘无法处理 slimRepo 中的合并。我可以以某种方式粉碎 slimRepo 的历史,并简单地合并到 fatRepo/ForkPoint 上吗?

git <turn into a single commit> slim/rootNode..slim/ForkPoint
git checkout fat/ForkPoint
git merge slim/branchHead
4

1 回答 1

1

是的,你是对的。

如果您可以提前识别文件,只需手动列出它们。

如果您需要从每次提交中选择大文件,您可以:

  • 使用索引过滤器(如上面的示例所示),但检查中的大文件$GIT_COMMIT,或
  • 使用树过滤器并简单地删除大文件

(或者当然你能想到的任何其他东西)。

索引过滤器要快得多,因为它允许您(和 git)跳过将每个要过滤的提交转换为工作树的杂乱事务,反之亦然。但是,如果要复制的提交很少,您将把时间和精力投入到总体回报很小的事情上。如果您希望采用这种方式,请注意您需要足够的引用才能$GIT_COMMIT从发生时可用的变量中提取eval(例如,请参见下面的脚本技巧,因为它已放入环境中)。

树过滤器很容易使用:在这种情况下,git 将原始提交提取到一个干净的空子目录中(默认情况下,在.git包含存储库的目录中创建一个子目录,但请参阅-d参数)并运行您的过滤器(在那个子目录中)。之后保留的任何文件都将与其他过滤器(如果有)一起放入新的提交中(按照文档中给出的顺序)。所以你的树过滤器可能只是:

find . -type f -size +10M -exec rm '{}' ';'

请注意,字符串是传递给的,eval因此有必要使用多个级别的引用。或者,您可以简单地通过完整路径名运行它:将您的脚本放在一个文件中,例如/tmp/cleanup.sh,使其可执行,然后使用:

git filter-branch --tree-filter /tmp/cleanup.sh ForkPoint..HEAD^

树过滤器会很慢,但您可能不太在意,尤其是当您的范围仅包含少数提交时。


编辑:通过查看存储在该提交中的树来查找特定提交(或其他树)中的大文件——这是你在索引过滤器中需要的——你可以使用这个 script-ette(经过轻微测试):

git ls-tree -lr $ref |
while read mode type hash size path; do
    [ $size -gt $limit ] && echo $size $path
done

$ref为($GIT_COMMIT在索引过滤器中) 和选择合适的值$limitecho将命令更改为git rm --cached -- $path以在过滤器中删除它们。(您不需要--ignore-unmatch,因为通过查看该提交的树可以找到找到的路径。)

git rev-list您可以通过首先使用准备一组 refs来查看这会做什么:

git rev-list ForkPoint..HEAD^ | /tmp/script

其中 /tmp/script 是:

check_tree() {
    git ls-tree -lr $1 |
    while read mode type hash size path; do
        [ $size -gt $limit ] && echo $size $path
    done
}

limit=1000000 # or whatever number

while read rev; do
    check_tree $rev
done

一旦找到所需的大小限制值,然后使用稍微修改的脚本(如上所述)作为实际的索引过滤器。

于 2014-07-29T06:02:40.313 回答