【问题标题】:How to remove old versions of media files from a git repository如何从 git 存储库中删除旧版本的媒体文件
【发布时间】:2011-09-15 13:17:15
【问题描述】:

我有一个 Git 存储库,其中包含几个巨大的媒体文件(图像和音频文件)。这些媒体文件的多个版本已陆续提交到 repo。这些文件是相同资产的连续精炼版本,它们具有相同的名称。

我只想在 Git 存储库中保留最新版本,因为它变得太大了。
最简单的方法是什么?
如何将这些更改正确传播到上游存储库?

【问题讨论】:

    标签: git git-rewrite-history


    【解决方案1】:

    查看 ProGit 书中Maintenance and Data Recovery 章节中关于“删除对象”的部分。它提供了有关如何从 git 存储库中删除对象的步骤。但请注意,它具有破坏性。

    【讨论】:

    • 我暂时将此答案标记为已接受,因为您链接的章节似乎是最详细、最直接且易于理解的解释。如果我不得不评论什么,那么本章中的信息似乎侧重于删除之后提交和删除的文件。我要问的是删除仍在项目中的旧版本文件。我想这个信息可以从章节中推断出来,但欢迎提供任何其他信息。
    • 这就是不以链接形式提供答案的原因。它已经关闭,现在答案基本上与“是”的响应一样有用
    • @Justin,Progit 书可在线免费获取。可以搜索它并查看我上面引用的章节。即使该链接已关闭,仍然可以从其他网站访问该书。
    【解决方案2】:

    如前所述,您将在这里重写历史记录,因此您必须让合作者(如果有)来做git rebase

    至于从历史记录中删除特定文件,Github has a nice walkthrough

    对于未来的解决方案,您应该考虑将二进制文件放在子模块中。

    Git 的子模块支持允许存储库作为子目录包含外部项目的签出。子模块保持自己的身份;子模块支持仅存储子模块存储库位置和提交 ID,因此克隆包含项目(“超级项目”)的其他开发人员可以轻松地克隆同一修订版的所有子模块。超级项目的部分签出是可能的:您可以告诉 Git 不克隆任何子模块、部分或全部子模块。

    https://git-scm.com/docs/git-submodule

    https://git-scm.com/book/en/v2/Git-Tools-Submodules

    【讨论】:

    • 感谢您的信息,子模块的东西看起来很有希望。我已经看过 Github 教程,但它的问题是它只是告诉你“运行这些命令”,但它并没有告诉你到底在做什么。
    【解决方案3】:

    旧线程,但以防其他人在这里绊倒......

    GitHub 和 Bitbucket 都推荐使用 BFG Repo-Cleaner

    见:
    GitHub: Remove Sensitive Data
    Bitbucket: Reduce Repository Size & Bitbucket: Maintaining a Git Repository

    删除超过 1 兆字节的文件以及不在 HEAD 中的 jpg、png 和 mp3 的示例:

    # First get the latest bfg.jar, then:
    $ git clone --mirror git://example.com/some-big-repo.git
    $ java -jar bfg.jar --strip-blobs-bigger-than 1M --delete-files '*.{jpg,png,mp3}' some-big-repo.git
    $ cd some-big-repo.git
    $ git reflog expire --expire=now --all && git gc --prune=now --aggressive
    $ git push
    

    注意:现在您已经推送了更新的版本,远程存储库也应该运行它git gc ...否则您不会看到大小减少。 (参见例如https://stackoverflow.com/a/28782154/3419541

    最后,重新克隆存储库,以确保您不会意外地重新提交旧的媒体文件 blob。

    【讨论】:

    • 对于我需要执行的最后一个命令git push --force origin <branch name, in my case master>(否则它会提示我重新集成我刚刚从本地存储库中删除的所有远程更改——我认为)。另外,我很傻,没有意识到如果我已经有一个最新的本地仓库克隆,那么 git clone 是不必要的:p
    【解决方案4】:

    我有一个脚本 (github gist here) 可以从 git 存储库的整个历史记录中删除一些不需要的文件夹,或者删除除最新版本之外的所有文件夹。

    假设所有 git 存储库都在 ~/repos 中是硬编码的,但这很容易改变。它还应该很容易适应处理单个文件。

    【讨论】:

    • 有趣的是......我在第一次检查 SO(和这个问题)后写了那个脚本,看看是否有预先存在的解决方案 :)
    【解决方案5】:

    据我所知,这是无法做到的,因为在 git 中,每次提交都依赖于 整个 历史记录的 contents。因此,摆脱旧的大文件的唯一方法是“重播”整个提交历史(最好使用相同的提交时间戳和作者),省略大文件。请注意,这将产生一个完全独立的提交历史记录。

    这显然不是一个非常可行的方法,所以教训可能是“不要使用 git 来版本巨大的二进制文件”。相反,您也许可以为文件创建一个单独的(忽略的)文件夹,并使用单独的系统对它们进行版本控制。

    【讨论】:

    • 这里重要的是,通过重写历史,您将拥有无法再相互推/拉的单独存储库。您必须克隆一个新的裸副本并覆盖origin,并让其他为您的项目做出贡献的人克隆一个新副本。
    • Aasmund:嗯,这个问题中最受好评的答案:stackoverflow.com/questions/5984428/… 让我认为这确实可以做到(尽管我不是 100% 确定)。 meagar:那完全没问题。我只想要一个清晰简单的方法来完成这个(这些天没有时间深入研究大量的 Git 文档)。
    • @meagar:是的;这就是我所说的“请注意,这将产生一个完全独立的提交历史”。 (不过,它的表述不是很好。)
    • @rsanchez:我不知道git filter-branch,但它确实看起来像我建议的自动化版本。同样,请注意,您最终将获得与旧历史不重叠的历史。但如果这是一个个人项目,那可能没问题。过滤后,您可以删除原始分支(在您 100% 确定过滤有效之后 - 我会在某处保留原始存储库的副本)并运行 git gc,这应该删除不存在的二进制文件历史的较长部分。
    猜你喜欢
    • 1970-01-01
    • 2011-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    相关资源
    最近更新 更多