gpt4 book ai didi

git - 仅在两次提交之间从 Git 历史记录中删除文件

转载 作者:太空狗 更新时间:2023-10-29 14:20:29 26 4
gpt4 key购买 nike

我正在尝试使用 filter-branch 从我的历史记录中删除一些大文件.我以前成功地使用过这个命令,但我目前在处理特定的边缘情况时遇到了麻烦。

问题是这些大文件从未真正删除,而是被具有相同路径的较小版本替换

据我所知,我相信我有一个独特的问题。

Git 日志

为了详细说明,这里是我的存储库的基本表示:

----- A ------ B ----------- HEAD

哪里:

A is the commit where the large files were introduced
B is the commit (about 30 later) where the large files were replaced with smaller ones
HEAD is thousands of commits forward of B (~2 years of active development)

Git 过滤分支

理论上,我应该能够做这样的事情:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filenames' <parent of A>..B 

我相信我应该使用 <parent of A>因为filter-branch不包括在内。 (我不确定我是否还需要使用 B 的父级,但这是我现在最不担心的事情)。

运行这个给我错误:

$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch filenames' <parent of A>..B 
Which ref do you want to rewrite?

所以我包括了--glob="refs/heads/master*"在似乎可以解决问题的命令末尾 ( source )。

执行完成后,文件已被完全删除 - 似乎 git 忽略了我指定的上限。

所以我想知道这种方法是否可行?

替代方法

我认为我应该列出一些其他的想法,以便可以将潜在的答案集中在解决问题上。

  1. 实用的方法是在 HEAD 处提交文件名更改,然后运行 ​​git filter-branch ... HEAD .但是,我的存储库中有许多分支正在积极开发中,我相信这种方法会非常困惑。
  2. 另一种方法可能是做类似 here 中描述的事情.引用:create a temporary branch to point at HEAD^, filter-branch it, then add a graft to stitch the remaining commit on top of it, then filter-branch HEAD and then remove the graft.

希望有人以前遇到过这个问题并可以提供他们的专业知识。

更新

我要删除的文件总计 ~500MB 所以我非常想删除它们,这是可以理解的!在我加入公司很久之前,它们就已经投入使用,并且是我们从内部 Mercurial 服务器迁移到 GitHub 的残余(我想将 500MB 推送到内部服务器不会像 GitHub 那样引人注目...)。

更新2

我一直在关注 twalberg 的第二个答案(我认为我以正确的方式使用它):

git filter-branch --index-filter '(( $(git rev-list <SHA-of-child-of-B> --not $GIT_COMMIT | wc -l) > 0 )) && git rm --cached --ignore-unmatch <filenames>' 

这会产生我期望的那种输出:

...
Rewrite dc8a4b29463bfa43c2f3efe0c6e5a29a5cc6e0ef (1071/5680)rm 'file1'
rm 'file2'
rm 'file3'
rm 'file4'
...

在(预期的?)错误结束之前:

Rewrite e6b712b57257e2edd0bb9fbbac59e4c9d7b5aa79 (1072/5680)index filter failed: (( $(git rev-list e6b712b --not $GIT_COMMIT | wc -l) > 0 )) && git rm -rf --ignore-unmatch <filename>

在哪里e6b712bB 的 child .

此时我假设一切正常,所以我对我的存储库进行本地文件系统克隆来测试它:

git clone file://<repo> <new repo>

对象的数量和包文件的大小减少了非常小的数量——我不确定为什么。通过运行 git count-objects -v针对原始存储库与具有 filter-branch 的存储库反对它:

原始存储库:

count: 0
size: 0
in-pack: 106640
packs: 1
size-pack: 815512
prune-packable: 0
garbage: 0

filter-branch ed 和文件系统克隆存储库:

count: 0
size: 0
in-pack: 96165
packs: 1
size-pack: 793656
prune-packable: 0
garbage: 0

我真的不确定为什么这仍然不起作用 - 也许我没有正确遵循建议的答案?

最佳答案

不幸的是,如果你真的想从你的存储库中删除这些对象(与简单地从当前和 future 的修订中删除它们相比),filter-branch 是这样做的方法,如果你是要重写提交 A,每个提交到每个分支头的在其历史中包含 A 的每个提交也必须重写,因为提交的提交哈希取决于提交该提交的每个父级的哈希值。如果您不重写包含 A 的所有分支,那么这些对象仍然是您可访问历史记录中某些提交的合法部分,并且它们不会被修剪。

对于在其历史中包含 A 的每个分支 BR,这应该有效:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filenames' BR --not A~1

将从 A 重写(通过修剪 A 父级的分支)到分支 BR 的当前尖端。不过,它会从所有这些提交中删除文件,即使它们已被较新的较小版本替换。为了仅在提交 B 之前删除它们,您可以像这样扩展过滤器脚本:

... --index-filter '(( $(git rev-list <SHA-of-child-of-B> --not $GIT_COMMIT | wc -l) > 0 )) && git rm ...' ...

这使用 rev-list 列出当前正在重写的提交之后的所有修订,直到 B 的子级,计算这些行,并且只执行 git rm如果一个或多个修订落在该范围内(当 $GIT_COMMIT == B 时,将打印一行 - 因此需要使用 B 的子项)。

即使对于单个分支来说,这也是一个相当大的变化,如果你有很多分支是在 A 或之后产生的,那么你需要做很多工作,所以你必须决定它是否最终值得它,或者如果您只需要一个更大的磁盘(您没有明确提到这些文件有多大)。

关于git - 仅在两次提交之间从 Git 历史记录中删除文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14837241/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com