背景
据研发同学反馈某次jenkins流水线编译代码时,一直不能检出代码,遂展开调查事故原因, 查看代码库就发现好家伙…代码存储竟然高达四百多兆, 这是个什么神仙代码库啊!!!
那么问题来了, 即便代码库很大为什么Jenkins拉取代码的时候会超时呢? 经过分析日志发现原来小丑竟是jenkins自己, 它居然弄了个十分钟超时的默认设置, 一般来说可以在Jenknins上修改超时时间来绕过这个问题. 但是由于我们平台的特殊性我们没办法马上改超时时间. 既然解决不了问题那么我们就想办法解决提出问题的人, 通过对代码库的进一步分析发现 有几个target目录特别大,没想到居然是研发同学在搞事情,连这中本地编译后生成的目录和文件都给提交了. 于是让研发同学删除后再试着拉取代码, 嗯… 结果可以说是不出所料依旧超时. 😰
原理
事情到这一步时候我们就需要了解一点git的原理了, Git 是一个内容寻址文件系统,核心部分是一个简单的键值对数据库(key-value data store)。 你可以向 Git 仓库中插入任意类型的内容,它会返回一个唯一的键,通过该键可以在任意时刻再次取回该内容。简单来说就是即使在代码中把大文件删除了.git 目录中仍然保存了大文件对象数据, 这导致了代码库占用存储过多,而且历史提交记录中仍然有对大文件的引用, 具体原理见 Git 内部原理 - Git 对象 Git 内部原理 - 维护与数据恢复
备用方案一, 精简代码库历史提交记录(推荐)
-
先将原来的代码库复制一份做个备份, 避免精简提交记录的时候误删除导致文件无法恢复 -
查看前五个最大的git对象, 可以根据自己需要修改tail -5 git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"
效果如下 user ~: git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"
c0e699fc5f6b32b6570c9f785d7c2f3c5b4954e2 target/test-report/src/main/resources/lib/aspose-words-15.8.0-jdk16.jar
9ee9c8d2497170f9f87d1ccf4e84e85e9240de1a target/test-sec/lib/rt.jar
ba7f1017e3e31904bc5be9d12b1fb3c2c4646fa3 target/test-kafka/litest/kafka_2.11-1.1.0.jar
234eb4a57e3a5c150db689a83a3b12e747ecb699 target/test-dia/doc/测试.docx
181aa66aeb5570c83c8947a7fab6339f04d8265e target/test-sec.zip
Git 往磁盘保存对象时默认使用的格式叫松散对象 (loose object) 格式 Git 时不时地将这些对象打包至一个叫 packfile 的二进制文件以节省空间并提高效率 而git verify-pack 命令就是用于显示已打包的内容 sort 命令中 -k 指定排序参照列, -n 依照数值的大小排序 tail 命令 指定输出项数 git rev-list 按照默认反向时间顺序,输出命令指定的commit objects --objects 列出的提交引用的任何对象的对象ID --all 全部匹配结果
-
修改上一次提交, 从这一步开始的操作比较危险, 所以再强调一遍做好备份 git commit --amend
-
删除需要删除的文件或文件夹 -
-
-
清理优化 git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now
git for-each-ref 输出指定位置所有reflog条目,--format 指定带有特定字符的Object git update-ref update reflog条目 git reflog expire 删除掉--expire 时间早的reflog条目 git gc --prune= 对指定日期之前的未被关联的松散对象进行清理 清理过后执行du -d 1 -h 查看空间占用降下来了
-
推送到远端仓库 执行git push --force --verbose --dry-run 查看模拟推送会执行的操作
--verbose 详细输出运行log --dry-run 做"真的update远程"以外所有工作 执行git push --force 会直接推送新的更新到远端仓库, 如果远端仓库是gitlab的在gitlab界面上会看到远端仓库的空间实际上是增大的, 但是我们直接git clone 后会发现和我们精简后的大小是一致的, 对于这种情况我们可以新建个干净的gitlab库之后再推送代码
更详细的操作过程见 https://www.cnblogs.com/bay1/p/10982254.html
备用方案二, git浅克隆
直接执行 git clone https://github.com/xxx/xxx.git --depth=1 克隆最近一次提交的完整代码, 会发现速度会快很多.git 只会保留最近的提交, 当然–depth的数值可以自定义的
其他
Jenkins上有git浅克隆的实现, 也有svn增量检出机制的实现 如下:
- git 浅克隆实现:
[$class: 'CloneOption', depth: 1, noTags: false, reference: '', shallow: true, timeout: 30] checkout([$class: "GitSCM", branches: [[name: "${GIT_BRANCH}"]], doGenerateSubmoduleConfigurations: false,
extensions: [[$class: "CleanBeforeCheckout", deleteUntrackedNestedRepositories: true],
[$class: 'CheckoutOption', timeout: 30],
[$class: 'CloneOption', depth: 1, noTags: false, reference: '', shallow: true, timeout: 30]],
submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${CERT_ID}", url: "$CODE_URL"]]])
- svn增量检出流水线实现:
workspaceUpdater: [$class: "UpdateWithCleanUpdater"] checkout([$class: "SubversionSCM", additionalCredentials: [], excludedCommitMessages: "", excludedRegions: "",
excludedRevprop: "", excludedUsers: "", filterChangelog: false, ignoreDirPropChanges: false, includedRegions: "",
locations: [[cancelProcessOnExternalsFail: true, credentialsId: "${CERT_ID}",
depthOption: "infinity", ignoreExternalsOption: true, local: ".", remote: "${CODE_URL}"]], quietOperation: true,
workspaceUpdater: [$class: "UpdateWithCleanUpdater"]])
svn检出策略请参考 https://www.cnblogs.com/wangle/p/14787202.html
参考
https://www.cnblogs.com/bay1/p/10982254.html https://git-scm.com/book/zh/v2/Git-内部原理-Git-对象 https://www.cnblogs.com/wangle/p/14787202.html
|