寻找并删除 Git 记录中的大文件

​近期要将git仓库迁移到github中,结果因为记录中包含大文件导致无法上传代码,所以本文来介绍查找和重写 Git 记录的命令:git rev-list, git filter-branch,用来找出大文件并且删除大文件。

首先通过 rev-list 来找到仓库记录中的大文件:

$ git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | awk '
/^blob/ {print substr($0,6)}' | awk '$2 >= 25*1024^2' | sort --numeric-sort --key=2 --reverse | cut --complement --char
acters=13-40 | numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

然后通过 filter-branch 来重写这些大文件涉及到的所有提交(重写历史记录):

git filter-branch -f --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch your-file-name' --tag-name-filter cat -- --all

Git 仓库的存储方式

如果你熟知 Git 的存储方式,跳过此节。

Git 仓库位于项目根目录的 .git 文件夹,其中保存了从仓库建立(git init)以来所有的代码增删。 每一个提交(Commit)相当于一个 Patch 应用在之前的项目上,借此一个项目可以回到任何一次提交时的文件状态。

于是在 Git 中删除一个文件时,Git 只是记录了该删除操作,该记录作为一个 Patch 存储在 .git 中。 删除前的文件仍然在 Git 仓库中保存着。直接删除文件并提交起不到给 Git 仓库瘦身的效果。

在 Git 仓库彻底删除一个文件只有一种办法:重写(Rewrite)涉及该文件的所有提交。 幸运的是借助 git filter-branch 便可以重写历史提交,当然这也是 Git 中最危险的操作。 可以说比 rm -rf * 危险一万倍。

从所有提交中删除一个文件

我清楚地记得曾提交过名为 recent-badge.psd 的文件。这是一个很大的 PhotoShop 文件,我要把它删掉。 filter-branch 命令可以用来重写 Git 仓库中的提交, 利用 filter-branch 的 --index-filter 参数便能把它从所有 Git 提交中删除。

$ git filter-branch -f --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch assets/img/recent-badge.psd' --tag-name-filter cat -- --all
Rewrite 2771f50d45a0293668a30af77983d87886441640 (264/982)rm 'assets/img/recent-badge.psd'
Rewrite 1a98ecb3f39e1f200e31754714eec18bc92848ce (265/982)rm 'assets/img/recent-badge.psd'
Rewrite d4e61cfb1d88187b0561d283e663b81b738df2c7 (270/982)rm 'assets/img/recent-badge.psd'
Rewrite 4ba0df06b26cf86fd39c2cda6b012c521cbc4dc1 (271/982)rm 'assets/img/recent-badge.psd'
Rewrite 242ae98060c77863f5e826ba7e1ec47

--index-filter 参数用来指定一条 Bash 命令,然后 Git 会检出(checkout)所有的提交, 执行该命令,然后重新提交。我们在提交前移除了 recent-badge.psd 文件, 这个文件便从 Git 的所有记录中完全消失了。

--all 参数告诉 Git 我们需要重写所有分支(或引用)。

你可能感兴趣的:(git,github)