你是不是也经历过这个场景?
正在修一个 bug,做到一半老板说有个紧急需求要先上。
你打开终端,准备切分支,结果 git checkout 直接报错:
error: Your local changes to the following files would be overwritten by checkout.
Please commit your changes before switching branches.
这时候你要么 git commit --amend 把半成品提交上去,要么 git stash 暂存起来。
很多人只知道 git stash 这一招,但真正用好它的人不多。今天聊聊 Git Stash 的实用技巧。
基础操作:三板斧
1. 暂存当前改动
git stash save "修复用户列表页面的样式问题"
注意这里用了 save 而不是 push。git stash save "message" 会给你的 stash 加个描述,方便后续查找。
2. 查看有哪些 stash
git stash list
stash@{0}: On main: 修复用户列表页面的样式问题
stash@{1}: On main: 临时修改数据库连接配置
stash@{2}: WIP on main: a3f8c21
3. 恢复暂存的内容
git stash pop
pop 会恢复 stash 内容并删除这条 stash 记录。如果你还想保留,用 apply:
git stash apply stash@{0}
# 内容恢复了,但 stash 记录还在
进阶技巧
只暂存部分文件
默认情况下 git stash 会暂存所有 tracked 文件的改动。但有时候你只想暂存一部分。
# 交互式选择哪些改动要暂存
git stash push -p
执行后,Git 会把你的改动拆成一个个 hunk,逐个问你"这个要不要 stash"。对于一个大 PR 中间突然要切分支的情况,这招特别好用。
暂存未跟踪的文件
git stash 默认不管 untracked 文件(新创建的、还没 git add 过的)。想连它们一起暂存:
git stash push -u
或者更激进的,把所有东西(包括 .gitignore 里的)都暂存:
git stash push -all
给 stash 打标签
当 stash 列表很长的时候,靠序号找就很痛苦。你可以给 stash 打标签:
git stash store -m "紧急修复:支付接口超时问题" $(git stash list | grep "支付" | awk '{print $2}' | tr -d ':')
不过更实用的方式是直接在 push 时加描述:
git stash push -m "支付接口超时修复 - 临时保存"
然后用 git stash list 就能直接看到描述,不用猜。
从 stash 创建新分支
这是很多人不知道的技巧。stash 里的代码可以直接变成一个新分支:
git stash branch fix/payment-timeout stash@{0}
这相当于做了三件事:
- 基于 stash 所在的分支创建新分支
- 应用 stash 内容
- 删除对应的 stash 记录
当你想在一个干净的分支上继续 stash 里的改动时,这招比手动 checkout + apply 省事多了。
日常管理
清除已合并的 stash
git stash drop stash@{0}
清空所有 stash
git stash clear
⚠️ 这个操作不可逆,执行前确认没有要保留的内容。
只保留最近 N 条
Git 本身没有这个命令,但可以配合脚本实现:
# 保留最新的 3 条 stash,其余全部删除
git stash list | tail -n +4 | while read line; do
hash=$(echo "$line" | awk '{print $2}' | tr -d ':')
git stash drop "$hash"
done
实战场景
场景一:多人协作的紧急 hotfix
你在开发 feature/user-profile 分支,已经改了一半。突然线上出了个 bug,需要马上修。
# 1. 保存当前进度
git stash push -m "用户资料页 - 进行中"
# 2. 切到 main 分支
git checkout main
# 3. 创建 hotfix 分支
git checkout -b hotfix/payment-fix
# 4. 修完 bug 后
git add .
git commit -m "修复支付超时问题"
git push origin hotfix/payment-fix
# 5. 回到原来的分支继续干活
git checkout feature/user-profile
git stash apply "用户资料页 - 进行中"
场景二:在多个分支间来回切换
比如你在两个不同的功能分支上各做了一半,想同时保留两边的进度。
# 在 feature-a 上
git stash push -m "feature-a 进度"
git checkout feature-b
# 在 feature-b 上也 stash
git stash push -m "feature-b 进度"
# 现在 stash list 里有两条,互不影响
git stash list
两边都恢复:
git checkout feature-a
git stash apply "feature-a 进度"
git checkout feature-b
git stash apply "feature-b 进度"
场景三:stash 冲突了怎么办
有时候 stash 的内容跟目标分支有冲突,git stash pop 会停下来让你手动解决。
# 冲突后,正常解决文件内容
# 然后标记为已解决
git add <冲突文件>
# 完成 stash 恢复
git stash drop
如果不想解决冲突,直接放弃这次 stash:
git stash drop stash@{0}
常见误区
误区一:stash 可以替代 commit
不行。stash 存在 .git 内部,不会被推送到远程。如果不小心清掉了 stash,那些改动就彻底没了。重要的改动一定要 commit。
误区二:git stash 会暂存所有东西
不会。它只暂存 tracked 文件的改动。新建的文件、.gitignore 里的内容都不会被 stash。需要用 -u 或 --all 参数。
误区三:stash 只能存一次
错了。你可以无限次 stash,它会形成一个栈。stash@{0} 是最新的,stash@{1} 是上一条,以此类推。
总结
Git Stash 是个被低估的功能。掌握这几个技巧,基本能覆盖 90% 的分支切换场景。
记住一个原则:stash 是临时手段,commit 才是正经事。
下次再遇到"改了一半要切分支"的情况,别再慌着 commit 半成品了。试试 stash,你会觉得世界清净很多。
你平时用 git stash 最多的是哪个场景?有没有什么独门小技巧?