讲解
这个场景每个开发者都遇到过:功能写到一半,代码还不能提交,突然要切去别的分支修个紧急 bug。直接切换,半成品的改动会跟着你跑(或者干脆被 Git 拦下)。git stash 就是为这一刻准备的:它把当前工作区和暂存区的改动打包收起来,工作区瞬间恢复到最近一次提交的干净状态,你可以安心切分支;事情办完切回来,git stash pop 把收起来的改动原样倒回来,继续刚才的工作。
stash 是一个栈,可以存多层:git stash list 查看所有储藏(stash@{0} 是最新的);git stash push -m "说明" 给储藏起名字,翻旧账时不用猜;git stash show -p stash@{1} 查看某层的内容;git stash pop 恢复最新一层并从栈里删掉,git stash apply 恢复但保留(适合要应用多次的情况);git stash drop 删除指定层,git stash clear 清空。默认只收已跟踪文件的改动,加 -u(--include-untracked)连新文件一起收。
stash 是「临时抽屉」而不是「长期仓库」:存了十几个 stash 几个月不清理,里面有什么早就忘了,而它们又不在任何分支上,极易丢失。用完就 pop,确认没用的及时 drop。另外如果确实想把半成品存档,更稳妥的方式是在功能分支上直接提交一个「wip」提交,之后用 rebase -i 整理掉——提交比 stash 可见、可推送、不易丢。
示例
echo "写到一半的功能" >> app.js
echo "临时笔记" > notes.txt
git status --short
git stash push -u -m "半成品功能"
git status --short
git stash list
git stash show --stat stash@{0}
git stash pop
git status --short
echo "另一处修改" >> docs.txt
git stash
git stash drop
git stash list
stash push -u 之后工作区恢复干净(连未跟踪的 notes.txt 也被收走);pop 之后两处改动原样回来。第二个储藏直接 drop 丢弃。
常见坑
- 新文件没被 stash 收走:默认不包含未跟踪文件,切换分支后新文件还在原地。需要时加 -u。
- pop 出冲突:收起改动后相关文件又被提交修改,pop 时可能冲突。按普通冲突解决,且注意冲突时该层 stash 不会自动删除,解决完手动 drop。
- 把 stash 当长期存储:stash 不在任何分支上,清理误删、换电脑都不会带走。半成品优先提交 wip,stash 只救急。
- 在错误的分支上 pop:stash 记录的是改动本身,不绑定原分支。pop 之前确认当前分支是你想应用的目标。
小结
stash 把未提交的改动收进栈里,换你一个干净工作区;push -u -m 收纳、list 查看、pop 恢复、drop 删除。它救急不救穷,长期存档请提交 wip。下一章系统学习撤销:reset 与 revert。