说个每天都在遇到的场景:功能正写一半,代码还没法运行,临时告警响了需要立刻切分支修。commit半成品吧,提交记录里多一条垃圾;不commit切分支吧,要么被Git拦住,要么把改到一半的文件带到别的分支去,搞乱后来人。这种时候,git stash就是我手里最顺手的一个工具。
stash这个词翻译过来是“隐藏、暂存”,但它干的事情比你想象中更聪明:把工作区和暂存区里所有未提交的改动打包,塞进一个专门的“储物柜”,然后让当前工作区回到干净状态。等你忙完手头的事,再一条命令把改动取回来,原封不动地继续写。
这篇文章就围绕stash展开,从最基础的用法讲到冲突排查、误删恢复这类进阶场景。内容基于我一个一个命令实测过的经验,适合刚接触Git的初学者,也适合天天用Git但没深入研究过stash细节的朋友。
1. 为什么说stash是“代码版的暂停键”
想理解stash的价值,先得理解Git工作区的三大状态。改动不是只存在一个地方:工作区是你的实际文件改动,暂存区是你git add后准备提交的内容,本地仓库是HEAD指向的最后一次提交。三者之间任何一层有差异,都可能影响切换分支、拉取代码、合并等操作。
1.1 痛点场景:改了一半代码不能走
举个例子,我正在开发一个登录模块,改了三个文件,还没改完,连编译都不通过。这时线上出现一个紧急问题,需要基于当前分支前端版本立刻修复并发布。如果我直接git checkout fix-branch,Git大概率会弹出Your local changes to the following files would be overwritten by checkout,直接拒绝切换。
如果强行通过git checkout -f切过去,我的半成品改动会被覆盖。不要指望能恢复回来,这个命令执行后丢失就是没了。还有一种解决办法是先把改动commit掉,但这样会在历史记录里留下一个“半成品的提交”,后续不管是rebase还是review都会很难受,代码Review阶段还会被同事追着问“这个提交为什么编译不过”。
1.2 stash的底层原理:它其实是一个特殊的提交
很多人以为stash只是把文件挪了个临时位置,其实不是。stash底层走的是Git对象系统:它会把当前工作区和暂存区的状态分别打包成Git对象,然后创建一个special commit,这个commit被挂在refs/stash引用下面。
每次执行git stash,旧的stash自动变成新stash的parent节点,形成一条栈式的链。这也解释了为什么可以保存多个stash,为什么git stash list看到的是一个从最近到最远的列表,以及为什么能通过git fsck找回一个误删的stash——因为底层毕竟是commit对象,只要没有被垃圾回收,就还有救。
理解了这层原理,后面处理冲突、找回误删stash时,思路会清晰很多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. stash基础操作手册:从保存到恢复
先过一遍最常用的命令。这些操作我基本每天都在用,不复杂,但几个参数选择的差别值得记一下。
2.1 三步走:存、查、取
第一个命令是git stash,不带任何参数的默认行为是:把所有已跟踪文件的改动打包,包括工作区的改动和暂存区中已add但尚未提交的改动,然后重置工作区,让文件恢复到你最后一次提交时的状态。
执行后你会发现工作区瞬间变得干干净净,所有未提交的改动从当前工作区消失。git status干净到让你一度怀疑自己是不是白写了半天代码。不用慌,改动没有丢,静静躺在stash栈里
