有时,我将DVD-rip放入一个网站项目中,而后不当心git commit -a -m ...
,而后,zap的回购膨胀了2.2个演出。 下次我进行一些编辑,删除视频文件并提交全部内容,可是压缩文件仍在历史记录中。 html
我知道我能够从这些提交开始分支,并将一个分支从新创建到另外一个分支。 可是,我应该怎么作才能将2个提交合并在一块儿,以便大文件不显示在历史记录中,并在垃圾回收过程当中清除? java
请注意,此命令可能具备很大的破坏性。 若是更多的人在回购上工做,他们都将不得不拉新的树。 若是您的目标不是减少大小,则不须要三个中间命令。 因为filter分支会建立已删除文件的备份,所以能够在其中保留很长时间。 git
$ 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
git filter-branch --tree-filter 'rm -f path/to/file' HEAD
对我来讲效果很好,尽管我遇到了与此处所述相同的问题,我经过遵循此建议解决了这个问题。 github
这本pro-git书包含一整章有关重写历史的内容 -看看filter-branch
/从“每次提交中删除文件”部分。 shell
这些命令在个人状况下有效: c#
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
与上述版本几乎没有什么不一样。 bash
对于那些须要将其推送到github / bitbucket的用户(我仅使用bitbucket进行了测试): less
# 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
使用BFG Repo-Cleaner ,这是git-filter-branch
一种更简单,更快的替代方法,专门用于从Git历史记录中删除不须要的文件。 编辑器
认真遵循使用说明 ,核心部分就是这样: ide
$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git
任何大小超过100MB的文件(不在您的最新提交中)都将从Git存储库的历史记录中删除。 而后,您可使用git gc
清除失效的数据:
$ git gc --prune=now --aggressive
BFG一般比运行git-filter-branch
至少快10-50倍,而且一般更易于使用。
彻底公开:我是BFG Repo-Cleaner的做者。
若是您已将历史记录发布给其余开发人员,那么您想要作的就是极具破坏性的。 有关修复历史记录后的必要步骤,请参见git rebase
文档中的“从上游Rebase恢复” 。
您至少有两个选择: git filter-branch
和交互式rebase,这两个都在下面说明。
git filter-branch
我从Subversion导入中获取大量的二进制测试数据时遇到了相似的问题,并写了有关从git存储库中删除数据的信息 。
说您的git历史记录是:
$ git lola --name-status * f772d66 (HEAD, master) Login page | A login.html * cb14efd Remove DVD-rip | D oops.iso * ce36c98 Careless | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html
请注意, git lola
是非标准但很是有用的别名。 使用--name-status
开关,咱们能够看到与每次提交关联的树修改。
在“ Careless”提交(SHA1对象名称为ce36c98)中,文件oops.iso
是偶然添加的DVD-rip,并在下一个提交cb14efd中删除。 使用上述博客文章中描述的技术,要执行的命令是:
git filter-branch --prune-empty -d /dev/shm/scratch \ --index-filter "git rm --cached -f --ignore-unmatch oops.iso" \ --tag-name-filter cat -- --all
选项:
--prune-empty
删除因为过滤操做而变为空的提交( 即 ,不更改树)。 在典型状况下,此选项会产生更清晰的历史记录。 -d
命名一个临时目录,该目录尚不用于构建过滤的历史记录。 若是您在现代Linux发行版上运行,则在/dev/shm
指定树将加快执行速度 。 --index-filter
是主要事件,在历史记录的每一步都针对索引运行。 您但愿删除oops.iso
不管它在哪里找到,但并不是全部提交中都存在。 git rm --cached -f --ignore-unmatch oops.iso
删除存在的DVD-rip,不然不会失败。 --tag-name-filter
描述了如何重写标签名称。 cat
的过滤器是身份操做。 您的存储库与上面的示例同样,可能没有任何标签,可是出于全面考虑,我包括了此选项。 --
指定git filter-branch
选项的结尾 --all
如下--
是全部裁判的简写。 像上面的示例同样,您的存储库可能只有一个ref(主文件),可是出于全面考虑,我包括了此选项。 通过一番搅拌,如今的历史是:
$ git lola --name-status * 8e0a11c (HEAD, master) Login page | A login.html * e45ac59 Careless | A other.html | * f772d66 (refs/original/refs/heads/master) Login page | | A login.html | * cb14efd Remove DVD-rip | | D oops.iso | * ce36c98 Careless |/ | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html
请注意,新的“ Careless”提交仅添加other.html
,而“ Remove DVD-rip”提交再也不位于master分支上。 标为refs/original/refs/heads/master
的分支包含您的原始提交,以防您出错。 要删除它,请按照“收缩存储库清单”中的步骤进行操做。
$ git update-ref -d refs/original/refs/heads/master $ git reflog expire --expire=now --all $ git gc --prune=now
对于更简单的选择,克隆存储库以丢弃不须要的位。
$ cd ~/src $ mv repo repo.old $ git clone file:///home/user/src/repo.old repo
使用file:///...
克隆URL复制对象而不是仅建立硬连接。
如今您的历史记录是:
$ git lola --name-status * 8e0a11c (HEAD, master) Login page | A login.html * e45ac59 Careless | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html
前两个提交(“索引”和“管理页面”)的SHA1对象名称保持不变,由于过滤操做未修改这些提交。 “ Careless”丢失了oops.iso
,“ Login page”有了新的父代,所以其SHA1 确实发生了变化。
具备如下历史:
$ git lola --name-status * f772d66 (HEAD, master) Login page | A login.html * cb14efd Remove DVD-rip | D oops.iso * ce36c98 Careless | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html
您想从“无忧无虑”中删除oops.iso
,就好像您从未添加过它同样,而后“删除DVD-rip”对您毫无用处。 所以,咱们计划进行交互式基础调整的是保留“管理员页面”,编辑“无忧无虑”并丢弃“删除DVD-rip”。
运行$ git rebase -i 5af4522
启动具备如下内容的编辑器。
pick ce36c98 Careless pick cb14efd Remove DVD-rip pick f772d66 Login page # Rebase 5af4522..f772d66 onto 5af4522 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. #
执行咱们的计划,咱们将其修改成
edit ce36c98 Careless pick f772d66 Login page # Rebase 5af4522..f772d66 onto 5af4522 # ...
也就是说,咱们用“ Remove DVD-rip”删除该行,并将“ Careless”上的操做更改成edit
而不是pick
。
保存退出编辑器后,在命令提示符处显示如下消息。
Stopped at ce36c98... Careless You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue
消息告诉咱们,咱们处于咱们要编辑的“ Careless”提交中,所以咱们运行两个命令。
$ git rm --cached oops.iso $ git commit --amend -C HEAD $ git rebase --continue
第一个从索引中删除有问题的文件。 第二个将“ Careless”修改或修改成更新的索引,而且-C HEAD
指示git重用旧的提交消息。 最后, git rebase --continue
继续进行其他的rebase操做。
这提供了如下历史记录:
$ git lola --name-status * 93174be (HEAD, master) Login page | A login.html * a570198 Careless | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html
这就是你想要的。