参考:
https://blog.csdn.net/Y0W1as5eg37urFdS/article/details/123539994
https://www.manongdao.com/article-2342370.html
概述
git 概述
Git 是一个分布式版本控制软件,最初由 「林纳斯·托瓦兹」 创作,于 2005 年发布。最初目的是为更好地管理 Linux 内核开发。Git 在本地磁盘上就保存着所有有关当前项目的历史更新,处理速度快。Git 中的绝大多数操作都只需要访问本地文件和资源,不用实时联网。
「Git LFS」(Large File Storage - 大文件存储)是可以把?乐、图?、视频等指定的任意文件存在 Git仓库之外,而在 Git 仓库中用一个占用空间 1KB 不到的文本指针来代替的小?具。通过把大文件存储在 Git 仓库之外,可以减小 Git 仓库本身的体积,使克隆 Git 仓库的速度加快,也使得 Git 不会因为仓库中充满大?件而损失性能。
使用 Git LFS ,在默认情况下,只有当前签出的 commit 下的 LFS 对象的当前版本会被下载。此外,也可以做配置,只取由 Git LFS 管理的某些特定文件的实际内容,而对于其他由 Git LFS 管理的?件则只保留文件指针,从而节省带宽,加快克隆仓库的速度;也可以配置?次获取大文件的最近版本,从而能方便地检查大文件的近期变动。
.git 目录
虽然 .git 这个隐藏目录并不算在代码体积之后,但是拉代码的时候,是需要拉下来的,因为里面包含之前的提交记录等信息。这就会导致下载速度变的很慢。
├── HEAD
├── branches
├── index
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ └── master
├── objects
│ ├── 88
│ │ └── 23efd7fa394844ef4af3c649823fa4aedefec5
│ ├── 91
│ │ └── 0fc16f5cc5a91e6712c33aed4aad2cfffccb73
│ ├── 9f
│ │ └── 4d96d5b00d98959ea9960f069585ce42b1349a
│ ├── info
│ └── pack
└── refs
├── heads
│ └── master
└── tags
- description:用于GitWeb程序
- config:配置特定于该仓库的设置
- hooks:放置客户端或服务端的hook脚本
- HEAD:指明当前处于哪个分支
- objects:Git对象存储目录
- refs:Git引用存储目录
- branches:放置分支引用的目录
.git 目录变大原因
- 当使用 git add 和 git commit 命令的过程中,Git 都会生成一个 Git 对象,称为 blob对象,存放在 objects 目录下,然后更新 index 索引,再然后创建 tree 对象,最后创建出了 commit 对象。这些 commit 对象指向了顶层 tree 对象以及先前的 commit 对象。
- 而上述创建出来的对象,都以文件的方式保存在 .git/objects 目录下。所以,当在使用的过程中,提交了一个体积特别大的文件,就会被 Git 追踪记录在 .git/objects 文件夹下面。
- 即使后面删除了这个体积特别大的文件,但其实 Git 只会记录删除的这个操作,并不会把文件从 .git 文件夹下面真正的删除,即 .git 文件夹完全不会变小。
解决方案
方案1:重建仓库
重建仓库的这种做法,算是一种比较一劳永逸且相对而言比较简单的方式。但是,这种做法一般情况下,都是不可行,除非是自己的本地项目。
方案2:删除大文件
直接找到 .git 目录下的大文件,将其删除掉,之后推送到远程代码库里面。这样做的前提是,删除所有其他分支,保留 master 或者 main 分支,并清空 git 服务器的当前项目所有分支,重新推送。这里需要注意的是,操作有风险,后果请自负。
-
使用在 git 项目的根目录鼠标右击使用 Git Bash Here 调出 Git 的命令窗口 -
找出 git项目 中较大的五个提交记录文件 git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -5
执行结果(当前以查询最大的五次做介绍): dbad6eb20d31a5aefe132b74b2137cd10105c574 blob 16684712 7287784 86721282
6c858bc93421b2db41dafc2bfd4eb82c77c50266 blob 17504576 8257957 47764046
416088453a2514ada98ba639af3ff298510b4246 blob 22216104 10854126 75719527
f0d8d3b476526af42b4e06f390a1b4925580e99b blob 22435760 10589160 16678516
553ba826b92c9d42acb1e586774ac697661588c9 blob 29814552 12998052 60871184
-
第一行的字母其实相当于文件的 id,用以下命令可以找出 id 对应的文件名 git rev-list --objects --all | grep dbad6eb20d31a5aefe132b74b2137cd10105c574
执行结果 dbad6eb20d31a5aefe132b74b2137cd10105c574 Pods/UMengUShare/UShareSDK/SocialLibraries/WeChat/WechatSDK/libWeChatSDK.a
-
删除大文件记录 git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch Pods/UMengUShare/UShareSDK/SocialLibraries/WeChat/WechatSDK/libWeChatSDK.a' --tag-name-filter cat -- --all
上面代码执行完毕后有可能会报以下错误 WARNING: git-filter-branch has a glut of gotchas generating mangled history
rewrites. Hit Ctrl-C before proceeding to abort, then use an
alternative filtering tool such as 'git filter-repo'
(https://github.com/newren/git-filter-repo/) instead. See the
filter-branch manual page for more details; to squelch this warning,
set FILTER_BRANCH_SQUELCH_WARNING=1.
Proceeding with filter-branch...
Cannot rewrite branches: You have unstaged changes.
如果出现以上错误可执行以下命令 (不报错则跳过此步) git stash
然后重新执行移除命令 执行结果 WARNING: git-filter-branch has a glut of gotchas generating mangled history
rewrites. Hit Ctrl-C before proceeding to abort, then use an
alternative filtering tool such as 'git filter-repo'
(https://github.com/newren/git-filter-repo/) instead. See the
filter-branch manual page for more details; to squelch this warning,
set FILTER_BRANCH_SQUELCH_WARNING=1.
Proceeding with filter-branch...
Rewrite 967ff01a8b2bc7d7f6c90630ede38a2135ba5813 (1/41) (0 seconds passed, remaiRewrite 9674de7f9f8ed029785421f2246bb9d41786cc49 (2/41) (0 seconds passed, remaiRewrite e04ab331167f24b7d26d69e169386e690081af74 (3/41) (0 seconds passed, remaiRewrite 997e93fdaff75162eda8e5c6ee6d3265ce61fe96 (4/41) (0 seconds passed,
Rewrite 429d321e2ee4c54d8d96b35a8e35d021bd8930f1 (35/41) (3 seconds passed, remaining 0 predicted) rm 'Pods/UMengUShare/UShareSDK/SocialLibraries/WeChat/WechatSDK/libWeChatSDK.a'
Ref 'refs/heads/master' was rewritten
Ref 'refs/remotes/origin/master' was rewritten
WARNING: Ref 'refs/remotes/origin/master' is unchanged
Ref 'refs/stash' was rewritten
-
彻底清除 rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
-
强制推送远程 git push --force --all
git remote prune origin
方案3:使用 git repo-clean 工具清理(亲测,推荐)
git repo-clean是用 Golang 开发的具备 Git 仓库大文件扫描,清理,并重写 commit 提交记录功能的 Git 拓展工具。
源码及下载安装详见:https://gitee.com/oschina/git-repo-clean
推荐使用二进制包安装,简单方便
使用:
有两种使用方式,一种是命令行,一种是交互式。
目前选项有如下:
-v, --verbose 显示处理的详细过程
-V, --version 显示 git-repo-clean 版本号
-h, --help 显示使用信息
-p, --path 指定Git仓库的路径, 默认是当前目录,即'.'
-s, --scan 扫描Git仓库数据,默认是扫描所有分支中的数据
-f, --file 直接指定仓库中的文件或目录,与'--scan'不兼容
-b, --branch 设置需要删除文件的分支, 默认是从所有分支中删除文件
-l, --limit 设置扫描文件阈值, 比如: '--limit=10m'
-n, --number 设置显示扫描结果的数量
-t, --type 设置扫描文件后缀名,即文件类型
-i, --interactive 开启交互式操作
-d, --delete 执行文件删除和历史重写过程
-L, --lfs 将大文件转换为Git LFS指针文件
命令行式用法:
git repo-clean --verbose --scan --limit=1G --type=tar.gz --number=5
加上 --delete 选项,则会批量删除扫描出的文件,并重写相关提交历史(包括HEAD)
git repo-clean --verbose --scan --limit=1G --type=tar.gz --number=5 --delete
注意:
- 若直接在git项目的根目录进入 bash 命令窗口使用 repo-clean 命令时,显示无 repo-clean 命令,则可以通过左下角【开始】输入 cmd 进入命令窗口,然后使用命令切换至 git 项目的根目录,再使用 repo-clean 命令
- 目前扫描操作和删除操作都是默认在所有分支上进行,而
--branch 选项只是指定删除时的分支,不能指定扫描时的分支。因此如果使用了这个选项指定了某个分支,可能从扫描结果中选择了另一个分支中的文件,因此不会有文件真正被删除。
方案4:使用 migrate 命令优化 .git 目录
迁移已有的 git 仓库,使用 git lfs 来进行管理。重写历史后的提交需执行 git commit --force,请确认在本地的操作合适无误后再进行提交。如有迁移至 git lfs 前的仓库有多份拷贝,其他拷贝可能需要执行 git reset --hard origin/master 来重置其本地的分支,注意执行 git reset --hard 命令将会丢失本地的改动
git lfs migrate :用来将当前已经被 GIT 储存库(.git)保存的文件以 LFS 文件的形式保存
$ git lfs migrate import --include-ref=master --include="*.zip"
$ git lfs migrate import --everything --include="*.rar,*.zip"
$ git lfs push --force
$ git reflog expire --expire-unreachable=now --all
$ git gc --prune=now
拓展
使用 lfs 管理大文件
比较好的避免上述问题的出现,就是及时使用 lfs 来追踪、记录和管理大文件。这样大文件既不会污染我们的 .git 目录,也可以让我们更方便的使用。
$ git lfs install
$ git lfs track "*.iso"
git lfs track "logo.png"
$ git add .gitattributes
$ git add .
$ git commit -m "Add some files"
$ git push origin master
同时,还有一个方法,就是灵活使用 .gitignore 文件,及时排除仓库不需要的特殊目录或者文件,从而不会让不应该存在的文件,出现在代码仓库里面
.DS_Store
node_modules
/dist
*.zip
*.tar.gz
|