1. 为什么会用到stash:工作区被打断的真实场景
先说一个我自己的真实经历。有次我在一个功能分支上改了差不多半天的代码,涉及六个文件,其中三个改动了一半还没编译通过。就在这个节骨眼上,线上环境出了个紧急问题,需要立刻切到主分支去修一个hotfix。当时我脑子里第一反应是:完蛋了,这半天的改动怎么办。
直接commit?代码是坏的,编译都过不了,提交上去就是污染历史。直接切分支?Git根本不会让你切,工作区和暂存区有未提交的改动,它会拦住你说“本地改动会被覆盖”。
那时候我刚用Git不久,对stash只停留在“听说过”的层面,差点就手动把改动文件一份份备份到桌面上,然后硬切分支。后来用了git stash,整个人都轻松了。一条命令,所有未提交的改动全部收起来,工作区干净得像是刚刚clone下来的仓库,你可以放心大胆地切分支、做hotfix、再切回来,然后一条命令恢复现场。
所以这篇东西我不打算写成枯燥的命令手册,而是想把这两年stash用在各种场景下的经验,包括怎么用、什么时候用、踩过哪些坑,完整地捋一遍。尤其是git stash配合分支切换、代码审查、多任务并行这些情况,用好了真的能省掉非常多心烦意乱的操作。
先明确一下stash解决的核心问题:它让你可以临时把工作区的“半成品”保存到一个独立的区域,让工作区恢复干净,同时又不需要提交任何不完整的代码。 换句话说,它解决的是“还没做完、暂时又做不下去”的保存问题。跟你把书本合上、夹个书签放在书架上是同一个道理,不是把这一页撕下来扔掉,也不是硬着头皮把半本书读完。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. stash基础操作全解:保存、查看、恢复、清除
2.1 stash保存的完整姿势,不只git stash一种
最基础最常用的就是直接执行git stash。不带任何参数时,它默认会把所有已跟踪文件的修改(包括已暂存和未暂存的改动)保存到stash栈中,然后工作区回到HEAD状态。注意这里有个关键点:默认情况下,它不会保存untracked文件。
什么叫untracked文件?就是那些你新建了但从来没有git add过的文件。很多人在这里吃过亏:新建了一个配置文件,改了半天,执行git stash,结果切完分支回来发现新文件还在,根本就没被stash存走。
这个设计其实是有意为之的。git stash默认逻辑是“把我正在修改的、已经在版本控制里的内容收起来”,而新建的、还没纳入版本控制的文件,Git认为它们不属于“正在做的修改”的一部分,可能只是临时测试用的东西。但实际工作中,新文件往往就是我们改动的一部分,所以更完整的保存命令应该这样用:
bash复制# 保存所有已跟踪文件的改动
git stash
# 保存所有改动,包含新建但未跟踪的文件
git stash -u
# 保存所有改动,包含未跟踪文件,同时包含被忽略的文件
git stash -a
这三个命令的区分特别重要。-u是--include-untracked,-a是--all。我自己最常用的就是git stash -u。因为我的习惯是开发时经常加一些临时的新文件来做调试,这些文件虽然是新的,但确实是我的工作成果,如果默认的git stash存不走它们,回头恢复的时候会发现工作区一半是恢复好的修改,一半还留着没动的新文件,很容易漏东西。
还有一个不太为人知但很实用的选项是git stash --keep-index。它的作用是:把工作区的改动存入stash,但保留暂存区的状态不变。我们经常会遇到这种场景:你已经把一部分改动用git add暂存了,形成了几个逻辑清晰的文件组,然后工作区还有另外一些改动不想现在处理。此时用--keep-index,stash会存走工作区的改动,但被暂存的内容不会动。
举个例子,我改了A、B、C三个文件,只有A是准备本次提交的内容,B和C是另一件事的改动。我执行git add A,再执行git stash --keep-index,结果就是B和C被存走,A仍然在暂存区,工作区里A的改动也依然保留。然后我可以临时基于A的内容做其他操作,回头再恢复B和C继续写。这个命令用得好,会让你对“暂存区”和“工作区”的理解上一个台阶。
2.2 查看与恢复:stash list、stash pop、stash apply
存好之后,怎么确认存了哪些东西?用git stash list,输出大概长这样:
code复制stash@{0}: WIP on feature/login: 3a4f6x2 完善登录接口参数校验
stash@{1}: WIP on master: dcnf9a1 修复首页白屏问题
stash@{2}: On feature/user: 原来不太规范的描述
每一条都是一个stash记录,最上面的是最近保存的。stash@{0}、stash@{1}这种编号就是每条记录的索引。默认查看具体某条stash改了什么内容,用`git s
