cul*_*rón 646 git version-control git-rebase git-rewrite-history
偶尔我会把一个DVD-rip放到一个网站项目中,然后不小心git commit -a -m ...,然后,zap,回购邮件被2.2演出臃肿.下次我做了一些编辑,删除了视频文件,并提交了所有内容,但是历史记录中的压缩文件仍然存储在存储库中.
我知道我可以从那些提交开始分支并将一个分支重新绑定到另一个分支.但是我应该怎么做才能将2个提交合并在一起,以便大文件没有在历史记录中显示并在垃圾收集过程中被清除?
Rob*_*ley 557
使用BFG Repo-Cleaner,这是一种更简单,更快速的替代方案,git-filter-branch专门用于从Git历史记录中删除不需要的文件.
仔细按照使用说明进行操作,核心部分就是:
$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git
Run Code Online (Sandbox Code Playgroud)
任何超过100MB的文件(不在最近的提交中)都将从Git存储库的历史记录中删除.然后,您可以使用git gc清除死数据:
$ git gc --prune=now --aggressive
Run Code Online (Sandbox Code Playgroud)
BFG通常比运行速度快至少10-50倍git-filter-branch,并且通常更易于使用.
完全披露:我是BFG Repo-Cleaner的作者.
Gre*_*con 535
如果您已将历史记录发布给其他开发人员,那么您想要做的事情具有很强的破坏性.修复历史记录后,请参阅文档中的"从上游Rebase恢复"以git 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
Run Code Online (Sandbox Code Playgroud)
请注意,这git lola是一个非标准但非常有用的别名.通过该--name-status开关,我们可以看到与每个提交相关的树修改.
在"粗心"提交(其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
Run Code Online (Sandbox Code Playgroud)
选项:
--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(master),但我包含此选项以实现完全通用性.经过一番搅拌,现在的历史是:
$ 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
Run Code Online (Sandbox Code Playgroud)
请注意,新的"Careless"提交仅添加other.html,并且"删除DVD-rip"提交不再在主分支上.标记的分支refs/original/refs/heads/master包含您的原始提交,以防您犯了错误.要删除它,请按照"收集存储库的清单"中的步骤进行操作.
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
Run Code Online (Sandbox Code Playgroud)
对于更简单的替代方法,克隆存储库以丢弃不需要的位.
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
Run Code Online (Sandbox Code Playgroud)
使用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
Run Code Online (Sandbox Code Playgroud)
前两个提交的SHA1对象名称("索引"和"管理页面")保持不变,因为筛选操作未修改这些提交."粗心"丢失了oops.iso,"登录页面"得到了一个新的父母,所以他们的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
Run Code Online (Sandbox Code Playgroud)
你想oops.iso从"粗心"中删除,好像你从未添加它,然后"删除DVD-rip"对你没用.因此,我们进入交互式rebase的计划是保持"管理页面",编辑"粗心",并丢弃"删除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.
#
Run Code Online (Sandbox Code Playgroud)
执行我们的计划,我们将其修改为
edit ce36c98 Careless
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
# ...
Run Code Online (Sandbox Code Playgroud)
也就是说,我们删除了"删除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
Run Code Online (Sandbox Code Playgroud)
正如消息告诉我们的那样,我们正处于我们想要编辑的"粗心"提交中,因此我们运行两个命令.
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
Run Code Online (Sandbox Code Playgroud)
第一个从索引中删除违规文件.第二个修改或修改"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
Run Code Online (Sandbox Code Playgroud)
这就是你想要的.
Gar*_*auh 172
为什么不使用这个简单而强大的命令?
git filter-branch --tree-filter 'rm -f DVD-rip' HEAD
Run Code Online (Sandbox Code Playgroud)
--tree-filter每次签出项目后,该选项都会运行指定的命令,然后重新生成结果.在这种情况下,您将从每个快照中删除名为DVD-rip的文件,无论它是否存在.
看到这个链接.
Sri*_*bat 74
(我看到这个问题的最佳答案是:https://stackoverflow.com/a/42544963/714112,这里复制,因为这个帖子在Google搜索排名中显得很高,但其他人没有)
此shell脚本显示存储库中的所有blob对象,从最小到最大排序.
对于我的样本回购,它的运行速度比其他版本快100倍.
在我信赖的Athlon II X4系统上,它只需一分钟即可处理带有5,622,155个对象的Linux内核存储库.
git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print substr($0,6)}' \
| sort --numeric-sort --key=2 \
| cut --complement --characters=13-40 \
| numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Run Code Online (Sandbox Code Playgroud)
当你运行上面的代码时,你会得到很好的人类可读输出,如下所示:
...
0d99bb931299 530KiB path/to/some-image.jpg
2ba44098e28f 12MiB path/to/hires-image.png
bd1741ddce0d 63MiB path/to/some-video-1080p.mp4
Run Code Online (Sandbox Code Playgroud)
假设您想要删除文件,a并b从每个可以访问的提交中删除HEAD,您可以使用以下命令:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' HEAD
Run Code Online (Sandbox Code Playgroud)
Kos*_*nos 37
这些命令适用于我的情况:
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
Run Code Online (Sandbox Code Playgroud)
它与上述版本略有不同.
对于那些需要将其推送到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
Run Code Online (Sandbox Code Playgroud)
小智 37
在SO中尝试了几乎每个答案之后,我终于找到了这个宝石,它快速删除并删除了我的存储库中的大文件并允许我再次同步:http://www.zyxware.com/articles/4027/how-to-delete -files永久性地从-您-本地和远程的Git储存库
CD到您的本地工作文件夹并运行以下命令:
git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all
Run Code Online (Sandbox Code Playgroud)
将FOLDERNAME替换为您要从给定git存储库中删除的文件或文件夹.
完成此操作后,运行以下命令以清理本地存储库:
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now
Run Code Online (Sandbox Code Playgroud)
现在将所有更改推送到远程存储库:
git push --all --force
Run Code Online (Sandbox Code Playgroud)
这将清理远程存储库.
Don*_*nat 29
这个线程中有很好的答案,但同时其中许多已经过时了。使用git-filter-branch不再推荐,因为它是很难使用和大库非常缓慢。
git-filter-repo 使用起来更快更简单。
git-filter-repo是一个 Python 脚本,可从 github 获得:https : //github.com/newren/git-filter-repo。安装后,它看起来像一个常规的 git 命令,可以通过git filter-repo.
你只需要一个文件:Python3 脚本 git-filter-repo。将其复制到包含在 PATH 变量中的路径。在 Windows 上,您可能需要更改脚本的第一行(请参阅 INSTALL.md)。您需要在系统上安装 Python3,但这不是什么大问题。
首先你可以运行
git filter-repo --analyze
Run Code Online (Sandbox Code Playgroud)
这有助于您确定下一步要做什么。
您可以在任何地方删除您的 DVD-rip 文件:
git filter-repo --invert-paths --path-match DVD-rip
Run Code Online (Sandbox Code Playgroud)
Filter-repo 真的很快。filter-branch 在我的计算机上花费了大约 9 个小时的任务,通过 filter-repo 在 4 分钟内完成。你可以用 filter-repo 做更多的好事。请参阅文档。
警告:在您的存储库副本上执行此操作。filter-repo 的许多操作无法撤消。filter-repo 将更改所有修改的提交(当然)及其所有后代的提交哈希,直到最后一次提交!
Joe*_*Joe 14
不使用:
git filter-branch
Run Code Online (Sandbox Code Playgroud)
此命令在推送后可能不会更改远程存储库。如果您在使用后进行克隆,您会发现没有任何变化,并且存储库仍然很大。看来这个命令现在已经很旧了。例如,如果您使用 https://github.com/18F/C2/issues/439中的步骤,则这将不起作用。
解决方案
该解决方案基于使用:
git filter-repo
Run Code Online (Sandbox Code Playgroud)
脚步:
(1) 找到 .git 中最大的文件(将 10 更改为您想要显示的文件数量):
git rev-list --objects --all | grep -f <(git verify-pack -v .git/objects/pack/*.idx| sort -k 3 -n | cut -f 1 -d " " | tail -10)
Run Code Online (Sandbox Code Playgroud)
(2) 通过传递要删除的文件的路径和名称来开始过滤这些大文件:
git filter-repo --path-glob '../../src/../..' --invert-paths --force
Run Code Online (Sandbox Code Playgroud)
或者使用文件的扩展名,例如过滤所有.zip文件:
git filter-repo --path-glob '*.zip' --invert-paths --force
Run Code Online (Sandbox Code Playgroud)
或者,例如,过滤所有 .a 库文件:
git filter-repo --path-glob '*.a' --invert-paths --force
Run Code Online (Sandbox Code Playgroud)
或您在步骤 1 中找到的任何内容。
(3)
git remote add origin git@github.com:.../...git
Run Code Online (Sandbox Code Playgroud)
(4)
git push --all --force
git push --tags --force
Run Code Online (Sandbox Code Playgroud)
完毕!!!
小智 10
请注意,此命令可能非常具有破坏性.如果更多的人正在处理回购,他们都必须拉新树.如果您的目标不是减小尺寸,则不需要三个中间命令.因为过滤器分支创建了已删除文件的备份,并且它可以在那里停留很长时间.
$ 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
Run Code Online (Sandbox Code Playgroud)
根据 GitHub文档,只需按照以下步骤操作:
选项 1:您不想保留大文件:
rm path/to/your/large/file # delete the large file
Run Code Online (Sandbox Code Playgroud)
选项 2:您希望将大文件保存在未跟踪的目录中
mkdir large_files # create directory large_files
touch .gitignore # create .gitignore file if needed
'/large_files/' >> .gitignore # untrack directory large_files
mv path/to/your/large/file large_files/ # move the large file into the untracked directory
Run Code Online (Sandbox Code Playgroud)
git add path/to/your/large/file # add the deletion to the index
git commit -m 'delete large file' # commit the deletion
Run Code Online (Sandbox Code Playgroud)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/your/large/file" \
--prune-empty --tag-name-filter cat -- --all
git push <remote> <branch>
Run Code Online (Sandbox Code Playgroud)
如果您知道您的提交是最近的,而不是通过整个树执行以下操作:
git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD
这会将其从您的历史记录中删除
git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all
Run Code Online (Sandbox Code Playgroud)
我遇到了一个bitbucket帐户,我不小心存储了我网站的巨大*.jpa备份.
git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all
MY-BIG-DIRECTORY使用相关文件夹重新填充以完全重写您的历史记录(包括标记).
来源:http://naleid.com/blog/2012/01/17/finding-and-purging-big-files-from-git-history
使用Git Extensions,它是一个 UI 工具。它有一个名为“查找大文件”的插件,可以在存储库中查找 Lage 文件并允许永久删除它们。
在使用此工具之前不要使用 'git filter-branch',因为它无法找到由 'filter-branch' 删除的文件(尽管 'filter-branch' 不会从存储库包文件中完全删除文件) .
我基本上做了这个答案的内容: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
Run Code Online (Sandbox Code Playgroud)
它没有用,因为我喜欢重命名和移动很多东西。所以一些大文件位于已重命名的文件夹中,我认为 gc 无法删除对这些文件的引用,因为tree对象中的引用指向这些文件。我真正杀死它的最终解决方案是:
# 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
Run Code Online (Sandbox Code Playgroud)
我的 repo (the .git) 从 32MB 更改为 388KB,即使过滤器分支也无法清理。
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
220657 次 |
| 最近记录: |