我不小心把一个dvd光盘放到了一个网站项目中,然后不小心提交-a -m…而且,快,回购膨胀了2.2 g。下次我做了一些编辑,删除了视频文件,并提交了所有内容,但压缩文件仍然在存储库中,在历史中。

我知道我可以从这些提交中启动分支,并将一个分支重置到另一个分支上。但是我应该怎么做才能合并两次提交,使大文件不显示在历史记录中,并在垃圾收集过程中被清理?


当前回答

这将从你的历史记录中删除它

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all

其他回答

这些命令在我的案例中起作用:

git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --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

它与上面的版本没有什么不同。

对于那些需要把这个推到github/bitbucket的人(我只用bitbucket测试了这个):

# WARNING!!!
# this will rewrite completely your bitbucket refs
# will delete all branches that you didn't have in your local

git push --all --prune --force

# Once you pushed, all your teammates need to clone repository again
# git pull will not work

Git filter-branch是一个功能强大的命令,你可以使用它从提交历史中删除一个巨大的文件。该文件将保留一段时间,Git将在下一次垃圾收集中删除它。 下面是从提交历史中删除文件的完整过程。为了安全起见,下面的进程首先在一个新分支上运行命令。如果结果是您所需要的,那么将其重置回您实际想要更改的分支。

# Do it in a new testing branch
$ git checkout -b test

# Remove file-name from every commit on the new branch
# --index-filter, rewrite index without checking out
# --cached, remove it from index but not include working tree
# --ignore-unmatch, ignore if files to be removed are absent in a commit
# HEAD, execute the specified command for each commit reached from HEAD by parent link
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch file-name' HEAD

# The output is OK, reset it to the prior branch master
$ git checkout master
$ git reset --soft test

# Remove test branch
$ git branch -d test

# Push it with force
$ git push --force origin master

这将从你的历史记录中删除它

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all

我基本上按照这个答案做了: https://stackoverflow.com/a/11032521/1286423

(对于历史,我复制粘贴在这里)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

这并没有起作用,因为我喜欢重命名和移动东西。一些大文件在重命名的文件夹中,我认为gc不能删除对这些文件的引用因为树对象中的引用指向这些文件。 我最终的解决方法是:

# First, apply what's in the answer linked in the front
# and before doing the gc --prune --aggressive, do:

# Go back at the origin of the repository
git checkout -b newinit <sha1 of first commit>
# Create a parallel initial commit
git commit --amend
# go back on the master branch that has big file
# still referenced in history, even though 
# we thought we removed them.
git checkout master
# rebase on the newinit created earlier. By reapply patches,
# it will really forget about the references to hidden big files.
git rebase newinit

# Do the previous part (checkout + rebase) for each branch
# still connected to the original initial commit, 
# so we remove all the references.

# Remove the .git/logs folder, also containing references
# to commits that could make git gc not remove them.
rm -rf .git/logs/

# Then you can do a garbage collection,
# and the hidden files really will get gc'ed
git gc --prune --aggressive

我的repo (.git)从32MB变成了388KB,即使过滤器分支也无法清理。

使用BFG Repo-Cleaner,这是一个更简单、更快的Git -filter-branch的替代方案,专门用于从Git历史记录中删除不需要的文件。

仔细按照使用说明,核心部分就是这样:

$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git

任何超过100MB大小的文件(不是最近提交的文件)都将从Git存储库的历史记录中删除。然后你可以使用git gc清除死数据:

$ git reflog expire --expire=now --all && git gc --prune=now --aggressive

修剪后,我们可以强制推送到远程repo*

$ git push --force

*注意:不能在GitHub上强制推送一个保护分支

BFG通常比运行git-filter-branch快10-50倍,而且通常更容易使用。

完全披露:我是好心眼巨人回收清理器的作者。