【问题标题】:After deleting a binary file from Git history why is my repository still large?从 Git 历史记录中删除二进制文件后,为什么我的存储库仍然很大?
【发布时间】:2012-06-30 15:09:58
【问题描述】:

因此,让我先说我知道与 Stackoverflow 上的主题有关的先前问题。事实上,我已经尝试了所有我能找到的解决方案,但我的仓库中有一个二进制文件拒绝被删除并继续大大增加我的仓库大小。

我尝试过的方法,

这两个都是 Darhuuk 对 Remove files from git repo completely 的回答推荐的

但是,在尝试了这两种解决方案之后,script to find large files in git 仍然会找到有问题的二进制文件。但是来自this answer 的脚本不再找到二进制文件的提交。这两个脚本都是由this answer 建议的。

在尝试删除之后,repo 仍然是 44mb,这对于相对较小的源来说太大了。哪些建议大文件脚本正确地完成了它的工作。我试过推到 github(我做了一个 fork 以防万一),然后做一个新的克隆,看看 repo 大小是否减小,但它仍然是相同的大小。

有人可以解释我做错了什么或建议替代方法吗?

我应该注意,我不仅对从本地 repo 中修剪文件感兴趣,我还希望能够修复 Github 上的远程 repo。

【问题讨论】:

  • 这些方法是否可能因为我有多个分支而不起作用?
  • 是...如果任何分支(包括通过 fetch 检索到的远程分支)具有对对象的引用,则不会将其修剪为不可访问。
  • 所以我想问题变成了,如何从从 Github 提取的 repo 中删除对象,然后将 repo sans 二进制文件推回?
  • 我对以下方法还没有任何运气,其他人可以提出解决方案吗?有没有一种工具可以从头开始重新创建 repo,没有二进制文件?
  • 另一个更新,我脸上有一些鸡蛋,我的本地历史重写没有成功,因为我没有使用文件的完整路径(我也可以使用路径通配符)。所以我可以缩小本地 repo 的大小(从 44mb 缩小到 1mb),但是在推送到远程 Github repo 之后,它仍然与带有二进制文件的 repo 一样大。

标签: git version-control github


【解决方案1】:

2017 年编辑:如果您正在阅读本文,您可能应该查看 BFG Repo-Cleaner


令人尴尬的是,我的本地存储库大小没有缩小的原因是因为我在 filter-branch 中使用了错误的文件路径。因此,虽然我感谢 J-16 SDiZ 和 CodeGnome 的回答,但我的问题出在椅子和键盘之间。

为了让这个问题不再是我愚蠢的纪念碑,并且对人们真正有用,我花时间写了一个在修剪回购后必须经历的步骤,以便重新获得回购在 Github 上。希望这可以帮助某人。


删除有问题的文件

要删除有问题的文件,请运行下面的 shell 脚本,基于 Github remove sensitive data howto

#!/usr/bin/env bash
git filter-branch --index-filter 'git rm -r -q --cached --ignore-unmatch '$1'' --prune-empty --tag-name-filter cat -- --all

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

我遍历了本地存储库上的每个分支并执行了此操作,但老实说,我不确定是否需要这样做,(您不需要在每个分支上都执行此操作)但是您确实这样做了下一步需要每个本地分支,所以请记住这一点。完成后,您应该会看到本地存储库中的大小减小。您还应该能够在 CodeGnome 的答案中运行 blob 脚本并查看有问题的 blob 删除。如果不是,请仔细检查文件名和路径并确保它们正确。

git filter-branch 实际上在这里所做的是在 repo 中的每次提交上运行引号中列出的命令。

脚本的其余部分只是清理旧数据的所有缓存版本。

推送修剪后的 repo

现在本地 repo 处于您需要它的状态,诀窍是将其备份到 Github 上。不幸的是,据我所知,没有办法从 Github 存储库中完全删除二进制数据,这是来自 Github sensitive data howto

的引用

请注意,强制推送不会删除远程仓库上的提交,它只是引入新的提交并移动分支指针以指向它们。如果您担心用户直接通过 SHA1 访问错误提交,则必须删除 repo 并重新创建它。

您需要重新创建 Github 存储库,这很糟糕,但好消息是重新创建存储库实际上非常容易。痛苦的是您还必须重新创建问题和 wiki 中的数据,我将在下面介绍。

我建议在 github 中创建一个新的 repo,然后在你准备好后用旧的 repo 将其切换出来。这可以通过将旧的重命名为“repo name old”,然后将新创建的 repo 的名称更改为“repo name”来完成。确保在创建新存储库时取消选中使用 README 进行初始化,否则您将无法处理干净的状态。

如果您完成了最后一步,您应该清理您的存储库并准备就绪。现在需要更改遥控器以匹配新的 Github 存储库位置。我通过直接编辑 .git/config 文件来做到这一点,尽管我确信有人会告诉我这样做不是正确的方法。

在进行推送之前,请确保您在本地 repo 中拥有所有要推送的分支和标签。准备好后,使用以下命令推送所有分支

git push --all
git push --tags

现在你应该有一个远程仓库来匹配你修剪的本地仓库。仔细检查所有数据以防万一。

现在,如果您不必担心问题或 wiki,您就完成了。如果您继续阅读。

在 wiki 上移动

Github wiki 只是与您的主存储库相关联的另一个存储库。因此,要开始在某处克隆您的旧 wiki 存储库。然后下一部分有点棘手,据我所知,您需要单击新存储库的 wiki 选项卡才能创建 wiki,但它会使用初始文件为新创建的 wiki 播种。所以我所做的,我不确定是否有更好的方法,将遥控器更改为新创建的 wiki repo 并使用

推送到新位置
git push --all --force

这里需要强制,否则git会抱怨当前分支的尖端不匹配。我认为这可能会使初始页面在 git repo 中处于分离状态,但它对 repo 大小的影响应该可以忽略不计。

解决问题

this answer 对此提出了建议。但是看看答案中链接的the script,它看起来相当不完整,有一个 TODO 用于评论导入,我不知道它是否会带来问题的状态。

因此,鉴于我有一个相当小的未解决问题队列,而且我不介意丢失已解决的问题,我选择手动解决问题。请注意,在 cmets 上正确归因于其他人是不可能做到这一点的。因此,我认为对于一个更成熟的大型项目,您需要编写一个更强大的脚本来完成所有内容,但对于我的特定情况,这不是必需的。

【讨论】:

    【解决方案2】:

    有人可以解释我做错了什么或建议替代方法吗?

    您是否尝试过应用 DMAIC? D优化、M测量、A分析、改进、C控制。

    D - 从 git 历史记录中删除文件后,我的仓库仍然很大。
    M - 使用git init 确定新回购的大小以建立基线。
    A - 识别、验证和选择根本原因。试用git-repo-analysis
    I - 识别、测试和实施解决方案。也许BFG Repo-Cleaner 会有所帮助。也许不会。
    C - 维持收益。看看Git LFS 之类的东西或者其他合适的控制方法。

    我还希望能够修复 Github 上的远程仓库。

    这取决于您选择如何解决问题。例如,当使用 BFG 从历史记录中修剪文件时,它会重写历史记录并更新提交 SHA,因此根据您的特定需求和期望的结果,这里会有一些让步。

    【讨论】:

      【解决方案3】:

      script to find large files in git 中的脚本检查.pack 文件——即原始对象存储库。第二个脚本显示不再引用大对象。如果你真的想清理它,你可以做一个gcrepack

      git gc --aggressive --prune=now
      git repack -A -d
      

      如果这仍然没有帮助,您可能在 远程分支中有对象引用,您可以尝试

      1. 找出哪个提交有这个对象,见Which commit has this blob?和做git branch -a --contains <commit-ish>
      2. 使用git branch -r -D branchname删除远程分支

      更新——什么是“远程分支”?

      • 当你执行git fetch / git pull 时,远程分支是 git 获取的东西。 (git pullgit fetch refspec + git merge remote-branch 相同。

      • 1234563远程到远程分支remotes/origin/master)。
      • 如果这个分支是由你创建的,删除也应该没问题——因为你应该有一个“正常”(跟踪)分支。 但是你应该再次确认这一点。

      【讨论】:

      • 不,我仍然看到这两个命令之后的文件,gc 命令已经在 Underhill 的脚本中 :(
      • 您对 .pack 文件是问题的看法是绝对正确的。绝大多数 repo 大小都在那个文件中。
      • @JamesMcMahon 好的,这意味着对象在远程分支中(或其他不在正常分支中的引用)。查看更新的答案
      • 我查看了您引用的脚本。似乎只检查包文件;它似乎对松散的物体没有任何作用。这不会使您的答案无效,但值得指出。
      【解决方案4】:

      假设您已经使用 git-filter-branch(1) 和朋友从历史记录中删除了 blob,Git 经常将内容保存在 reflog、packfile 和松散的存储库对象中。删除这些未引用对象的咒语是:

      git prune --expire=now
      git reflog expire --expire-unreachable=now --rewrite --all
      git repack -a -d
      git prune-packed
      

      如果您已完成此操作并且仍然拥有比您认为应该更大的存储库,那么您仍然在存储库中某处引用了您的 blob。您必须返回到第一步并删除它们。这可能会有所帮助:

      # List all blobs by size in bytes.
      git rev-list --all --objects   |
          awk '{print $1}'           |
          git cat-file --batch-check |
          fgrep blob                 |
          sort -k3nr
      

      【讨论】:

      • 我不确定我是否有旧版本的 Git,但rev-list 只为我输出哈希值,因此awk 管道是不必要的。
      • prune 和 reflog 的内容已经在 Underhill 的脚本中。即使有额外的选择也没有运气。
      • 我运行了你的命令,但我的 repo 中还有一个大文件。我在上一个命令中找到了你的 blob,但我不知道现在该做什么。
      • 这个建议适用于我的我的本地存储库,但我仍然不确定如何将它传播到我的远程。 git push <path/to/remote> 只会告诉我一切都是最新的。从远程连续克隆仍然很大。
      • @worldsayshi 如果您进行了强制推送,则不应克隆无法访问的对象。但是,要实际删除打包或可访问的对象,您必须直接在遥控器上执行命令。您不能使用客户端/服务器命令执行存储库手术;这是一项功能。
      猜你喜欢
      • 2011-10-16
      • 2021-01-09
      • 2019-03-17
      • 2014-06-19
      • 2020-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多