尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

19 — 贮藏与清理:stash 是抽屉,gc 是打包箱

19 — 贮藏与清理:stash 是抽屉,gc 是打包箱 19 — 贮藏与清理stash 是抽屉gc 是打包箱摘要本章介绍 Git 中两个实用工具git stash用于临时贮藏未提交的改动像把桌面物品扫进抽屉方便切换分支处理紧急任务git gc用于垃圾回收和打包像整理档案柜将散落的小对象压缩成 pack 文件以节省空间。通过对比表格、动手实验和真实场景帮助读者掌握 stash 的暂存与恢复流程、gc 的安全清理机制并建立安全使用习惯。写在前面这一章要解决什么你有没有遇到过这种情况正在写功能写到一半突然老师说「先修一下这个紧急 bug」。你想切到别的分支去修 bug但当前分支的代码还没写完、不想提交。怎么办这就是git stash存在的意义——把没写完的代码暂时藏进抽屉里等修完 bug 再拿出来继续写。这一章还讲git gc垃圾回收——仓库用久了会越来越大gc 就像打包箱把散落的小文件打包压缩。学完后你应该能用git stash临时藏起没写完的改动用git stash pop拿回之前藏的改动理解 stash 底层是特殊的 commit知道什么时候该用git gc理解包文件pack是什么读者设定大一同学已经会用分支和基本命令但还没用过 stash 和 gc。1. 定位为什么要学贮藏和清理1.1 一句话先记住stash 把桌面上的东西暂时扫进抽屉等会儿再拿出来gc 把档案柜里散落的文件打包装箱节省空间。1.2 不知道 stash 会怎样没有 stash有 stash写到一半想切分支Git 不让有未提交的改动git stash藏起来随时切只好先提交一个「写了一半」的存档不需要提交半成品保持历史干净或者把改动复制到别的地方保存一条命令搞定不用手动复制忘了复制到哪里了git stash list随时查看所有藏起来的东西1.3 和你已经会的事对比你已经会的和这一章的关系第 04 章的git restorerestore 是丢弃改动stash 是暂时藏起来以后还用第 05 章的分支切分支时经常需要先 stash第 10 章的对象模型stash 底层就是特殊的 commit 对象2. 本质stash 到底做了什么2.1 stash 的底层原理当你执行git stash时Git 做了这些事把工作区和暂存区的差异保存为一个特殊的 commit这个 commit 有两个 parent工作区状态和暂存区状态把它存在refs/stash引用下把工作区和暂存区恢复到 HEAD 的状态白话你把桌面上没做完的作业放进抽屉桌面恢复到上次交作业的状态。抽屉里的作业随时可以拿出来。2.2 stash 的家族命令作用白话git stash藏起当前改动把东西扫进抽屉git stash list查看所有藏起来的东西打开抽屉看看里面有什么git stash pop拿回最近藏的改动从抽屉里拿出最近放进去的东西git stash apply拿回改动但不删除 stash 记录从抽屉里复制一份原件还在git stash drop删除某个 stash 记录把抽屉里的东西扔掉git stash clear删除所有 stash 记录清空整个抽屉2.3 stash 可以多次使用gitstash list输出类似stash{0}: WIP on main: a1b2c3 添加登录页面 stash{1}: WIP on feature: d4e5f6 修改样式 stash{2}: WIP on main: h7i8j9 临时实验白话翻译抽屉里有 3 样东西stash{0}是最近放进去的。3. gc垃圾回收和打包3.1 为什么需要 gc你的仓库用久了.git/objects/里会有很多小文件每次提交都会新增 blob、tree、commit 对象reset、rebase 后可能留下「悬空」的对象没有引用指向的这些对象散落在大量小文件里占空间、读写慢3.2 gc 做了什么git gc做两件事打包pack把大量小对象合并成一个大文件.pack同时生成索引.idx清理删除真正不需要的悬空对象超过 2 周、没有引用指向的白话打包 把散落的文件装进压缩包清理 把确认没人要的废纸扔掉3.3 gc 会丢数据吗不会。gc 只会删除同时满足以下条件的对象没有任何引用指向它reflog 里也没有记录已经超过宽限期默认 2 周如果你刚做了一个reset --hard然后立刻git gc——别担心reflog 里有记录gc 不会删。3.4 git repack 和 git prune命令作用白话git gc打包 清理大扫除git repack只做打包只把文件装箱git prune只做清理丢弃无用对象git gc --aggressive更彻底的打包耗时更长深度清洁4. 动手准备建一个可丢弃的练习目录mkdirlearn-git-19cdlearn-git-19gitinit-bmainecho第一版f.txtgitaddf.txtgitcommit-m第一次提交演示身份Ada Example adaexample.com5. 跟着做实验 1stash 基本流程# 开始写新功能但不提交echo新功能代码feature.txtgitaddfeature.txt# 突然要修 bug先藏起来gitstash# 白话翻译# Saved working directory and index state WIP on main: ... 第一次提交# 查看桌面——改动不见了gitstatus# 输出nothing to commit, working tree clean# 查看抽屉里有什么gitstash list# 输出stash{0}: WIP on main: ... 第一次提交# 修完 bug 后拿回之前的改动gitstash pop# 查看桌面——改动回来了gitstatus# feature.txt 又出现了实验 2带消息的 stashecho另一个功能feature2.txtgitaddfeature2.txt# 给 stash 加个备注方便以后辨认gitstash push-mfeature2 写到一半实验 3观察 gc 的效果# 先看看 .git/objects 有多少文件find.git/objects-typef|wc-l# 运行 gcgitgc# 再看文件数量大幅减少find.git/objects-typef|wc-l# 查看 pack 文件ls.git/objects/pack/# 输出类似pack-xxx.idx pack-xxx.pack6. 命令分组stash 相关命令作用注意git stash藏起改动默认不包括未跟踪的文件git stash -u藏起改动包括未跟踪文件新建的文件也会藏git stash push -m 备注带备注的 stash方便以后找git stash list列出所有 stash最近的在最上面git stash pop取出并删除最近 stash如果有冲突会保留git stash apply stash{n}取出但不删除可以多次 applygit stash drop stash{n}删除某个 stash删了就没了git stash clear清空所有 stash谨慎使用git stash branch 新分支名从 stash 创建新分支适合 stash 冲突时gc 相关命令作用注意git gc打包 清理日常足够git gc --aggressive深度打包大仓库才需要耗时长git prune只清悬空对象gc 的子步骤git repack只打包gc 的子步骤git count-objects查看对象统计看 repo 有多大7. 对照表stash pop vs apply维度stash popstash apply取出改动是是删除 stash 记录是否冲突时stash 记录保留需要手动处理stash 记录保留需要手动处理用哪个取出后不需要再用的取出后还想保留原 stash 的stash vs commit维度git stash临时 commit需要写说明吗不需要可以加 -m需要在 log 里能看到吗不能除非用stash list能适合场景临时存放很快会取出来稍微正式一点的保存点可以跨分支吗可以可以8. 安全习惯规矩为什么stash 前先看git status确认你知道藏了什么不要长期依赖 stashstash 不是长期存储超过 1 周就该提交或删了git stash pop遇到冲突别慌手动解决冲突就行stash 记录还保留着gc 前确认 reflog 里有重要记录gc 不会删有引用的对象但了解原理更安心不要频繁手动git gcGit 会自动 gc手动执行只在仓库很大时需要9. 真实场景场景一写到一半要切分支修 bug# 写到一半echo新功能feature.txt# 突然要修 buggitstash push-mfeature 写了一半gitswitch hotfix-branch# 修 bug……gitadd.gitcommit-m修复紧急 buggitswitch main# 拿回之前的改动gitstash pop场景二stash 跨分支迁移改动你在 wrong-branch 上写了一些代码发现应该写在 right-branch 上gitstashgitswitch right-branchgitstash pop场景三仓库越来越大的处理# 查看仓库大小du-sh.git# 查看对象数量gitcount-objects-v# 如果对象很多运行 gcgitgc# 再次查看大小du-sh.git# 应该变小了10. 进阶补充首读可跳过10.1 stash 的底层实现stash 实际上是 1-3 个 commit 对象stash{0}的第一个 parent 是原分支的 HEAD commit如果暂存区有改动第二个 parent 记录暂存区状态如果用了-u第三个 parent 记录未跟踪文件10.2 部分暂存# 只 stash 某个文件gitstash push-m只藏 style.css-- style.css10.3 pack 文件的增量Git 的 pack 文件采用增量存储如果两个版本的文件只差几个字节pack 只存差异部分非常节省空间。11. 小实验实验 Astash 基本流程修改一个文件但不要提交git stash藏起来确认工作区干净git stash pop取回来确认改动恢复了通过标准改动能完整藏起和取回。实验 B多次 stash做第一组改动git stash push -m 改动1做第二组改动git stash push -m 改动2git stash list看到两条记录git stash apply stash{1}取回第一条git stash drop stash{1}删除第一条通过标准能管理多条 stash 记录。实验 C观察 gc建仓库做 20 次提交git count-objects -v记录对象数量git gc再次git count-objects -v对比变化通过标准理解 gc 把松散对象打包成了 pack 文件。12. 常见问题问stash 会在 push 时推到远程吗不会。stash 是纯本地的不会影响远程仓库。问stash 最多能存多少个没有硬性限制但建议不超过 5-10 个。太多会导致混乱。超过 1 周不用的 stash 应该提交或删除。问stash pop 遇到冲突怎么办和 merge 冲突一样手动解决冲突然后git add标记已解决。stash 记录会保留因为 pop 没有成功完成解决完如果你不需要这个 stash 了手动git stash drop。问gc 会删我还没提交的代码吗不会。gc 只删「没有任何引用指向、reflog 里也没有记录、超过宽限期」的对象。你工作区里的改动不受 gc 影响。问什么时候需要手动 gc通常不需要——Git 会在合适的时机自动执行。只有仓库特别大或者你刚做了大量清理工作时才需要手动执行。问git stash -u和git stash有什么区别git stash只藏已跟踪文件的改动。git stash -u还会藏新建的未跟踪文件。如果你新建了一个文件还没git add普通 stash 不会藏它。13. 总结13.1 一页速记项目要点stash把没写完的代码暂时藏起来等会儿取回来stash pop取出并删除stash apply取出但保留stash list查看所有藏起来的东西gc打包散落对象 清理无用对象不会丢数据pack把很多小文件压缩成一个大文件13.2 本系列中的位置17 拣选与还原 → 18 重置三兄弟 → 19 贮藏与清理你在这里 → 20 远程进阶 ↑ 「暂时放一放」和「打扫卫生」13.3 思维升华stash 是 Git 给你的「等我一下」按钮。写到一半被打断不要慌也不要急着提交半成品——stash 一下等会儿回来继续。13.4 延伸阅读Pro Git — 贮藏与清理git-stash 文档git-gc 文档git-count-objects 文档本仓库图示署名assets/diagrams/ATTRIBUTION.md13.5 检查清单能用 stash 藏起改动并取回知道 stash list / pop / apply / drop 的区别理解 stash 底层是特殊的 commit知道 gc 做了什么打包 清理知道 gc 不会删有用的数据完成了实验 A、B、C
返回列表