Git + Gerrit 第七课:stash 临时保存工作区修改

本节目标

这一节学习 Git 中非常实用的命令:stash

你要理解这些问题:

复制代码
什么是 stash?
什么时候需要 stash?
为什么切换分支前要先看工作区是否干净?
如何临时保存未完成代码?
如何恢复 stash?
stash pop 和 stash apply 有什么区别?
如何查看、删除、清理 stash?
Gerrit 工作流中 stash 有什么用?

本节重点命令:

复制代码
git status
git stash
git stash push -m "说明"
git stash list
git stash show
git stash show -p
git stash pop
git stash apply
git stash drop
git stash clear

1. 为什么需要 stash

真实开发中,经常会遇到这种情况:

复制代码
你正在 feature/login 分支写登录功能。
代码写到一半,还不能提交。
突然同事说 master 上有一个紧急 bug 需要你马上修。

这时你想切换到 masterhotfix 分支。

但你的工作区还有未完成修改。

如果直接切分支,可能出现:

复制代码
error: Your local changes to the following files would be overwritten by checkout

意思是:

复制代码
你当前的本地修改可能会被切换分支覆盖,Git 阻止你继续操作。

这时就可以使用:

复制代码
git stash

它的作用是:

复制代码
把当前未提交的修改临时保存起来,让工作区恢复干净。

2. stash 是什么

stash 可以理解为:

复制代码
Git 提供的临时储藏柜。

你可以把还没完成、不适合提交的修改先放进去。

等你处理完其他事情,再把它取回来。

流程是:

复制代码
工作区有未完成修改
        |
        v
git stash
        |
        v
工作区变干净,可以切分支或拉代码
        |
        v
git stash pop / git stash apply
        |
        v
恢复之前的修改

注意:

复制代码
stash 不是正式提交。
stash 只是临时保存。

不要把 stash 当成长期保存代码的地方。

3. stash 适合什么场景

常见适用场景:

  • 代码写到一半,需要临时切换分支

  • 当前修改还不适合 commit

  • pull/rebase 前需要保持工作区干净

  • 需要临时测试另一个分支

  • 需要快速修复紧急 bug

  • 想暂时收起一些实验性修改

例如:

复制代码
你正在开发功能 A。
产品突然说线上功能 B 有紧急问题。
你可以 stash 功能 A 的半成品,然后切到 hotfix 分支修问题。

4. stash 不适合什么场景

不建议把 stash 用在这些场景:

  • 长期保存重要代码

  • 替代 commit

  • 保存已经完成的功能

  • 保存多人需要共享的代码

  • 保存你自己也说不清楚的临时修改

原因是:

复制代码
stash 没有 commit 那么清晰。
stash 多了以后很容易忘记每一个 stash 是什么。

如果一段代码已经有明确意义,最好提交:

复制代码
git add .
git commit -m "清楚描述本次修改"

如果只是临时没做完,再使用 stash。

5. 使用 stash 前先看状态

使用 stash 前,先执行:

复制代码
git status

你可能看到:

复制代码
Changes not staged for commit:
  modified: readme.md

表示:

复制代码
readme.md 有未暂存修改。

也可能看到:

复制代码
Changes to be committed:
  modified: readme.md

表示:

复制代码
readme.md 已经进入暂存区。

普通 git stash 会保存:

复制代码
已跟踪文件的工作区修改
已暂存修改

但默认不一定保存未跟踪的新文件,这一点后面会讲。

6. 最基本的 stash

执行:

复制代码
git stash

等价于:

复制代码
git stash push

它会把当前修改保存起来。

然后执行:

复制代码
git status

通常会看到:

复制代码
nothing to commit, working tree clean

意思是:

复制代码
工作区已经干净了。

这时你就可以安全切换分支:

复制代码
git switch master

或者:

复制代码
git switch main

7. 给 stash 添加说明

直接使用:

复制代码
git stash

生成的说明可能比较简单。

更推荐写清楚原因:

复制代码
git stash push -m "临时保存登录功能开发"

这样以后查看 stash 列表时更容易知道它是什么。

查看 stash:

复制代码
git stash list

你可能看到:

复制代码
stash@{0}: On feature/login: 临时保存登录功能开发

其中:

复制代码
stash@{0}

表示最新的一条 stash。

8. 查看 stash 列表

执行:

复制代码
git stash list

示例输出:

复制代码
stash@{0}: On feature/login: 临时保存登录功能开发
stash@{1}: On bugfix/order: 临时保存订单修复
stash@{2}: WIP on master: abc1234 添加基础配置

编号规则:

复制代码
stash@{0} 是最新的 stash。
stash@{1} 是更早的一条。
stash@{2} 更早。

注意:

复制代码
每新增一条 stash,旧 stash 的编号可能会变化。

所以使用前要先看:

复制代码
git stash list

9. 查看 stash 内容

查看某条 stash 改了哪些文件:

复制代码
git stash show stash@{0}

查看具体 diff:

复制代码
git stash show -p stash@{0}

如果只看最新 stash,也可以:

复制代码
git stash show
git stash show -p

建议恢复 stash 前先看内容:

复制代码
git stash show -p stash@{0}

避免恢复错 stash。

10. 恢复 stash:pop

最常用的恢复命令是:

复制代码
git stash pop

它的作用是:

复制代码
恢复最新一条 stash,并从 stash 列表中删除它。

也就是说:

复制代码
pop = apply + drop

如果你想恢复指定 stash:

复制代码
git stash pop stash@{1}

注意:

复制代码
pop 成功后,这条 stash 会从列表里移除。

11. 恢复 stash:apply

另一个恢复命令是:

复制代码
git stash apply

它的作用是:

复制代码
恢复最新一条 stash,但不删除 stash 记录。

如果恢复指定 stash:

复制代码
git stash apply stash@{1}

适合这些场景:

复制代码
你不确定恢复后是否正确。
你想保留 stash 作为备份。
你想把同一份修改应用到多个分支。

12. pop 和 apply 的区别

命令 恢复修改 删除 stash 记录 适合场景
git stash pop 确认只需要恢复一次
git stash apply 不会 想先保留备份

简单记忆:

复制代码
pop:取出来,并从储藏柜删除。
apply:复制出来,储藏柜里还保留。

新手更推荐先用:

复制代码
git stash apply

确认没问题后再删除 stash:

复制代码
git stash drop stash@{0}

13. 删除 stash

删除指定 stash:

复制代码
git stash drop stash@{0}

删除所有 stash:

复制代码
git stash clear

注意:

复制代码
git stash clear 会清空所有 stash。
新手不要随便执行。

如果不确定某条 stash 是否还有用,先看:

复制代码
git stash show -p stash@{0}

确认不需要了,再删除。

14. stash 与未跟踪文件

默认情况下,git stash 主要保存已被 Git 跟踪的文件修改。

如果你新建了一个文件:

复制代码
new-file.txt

但还没有 git add,它属于:

复制代码
Untracked files

普通:

复制代码
git stash

可能不会保存这个未跟踪文件。

如果想连未跟踪文件一起保存,可以使用:

复制代码
git stash push -u -m "保存包含新文件的修改"

其中:

复制代码
-u = include untracked

意思是:

复制代码
包含未跟踪文件。

15. stash 与忽略文件

如果还想把被 .gitignore 忽略的文件也保存进去,可以使用:

复制代码
git stash push -a -m "保存所有修改"

其中:

复制代码
-a = all

它会包含:

复制代码
已跟踪文件修改
未跟踪文件
被忽略文件

新手一般不建议使用 -a

因为可能会把:

复制代码
bin/
obj/
node_modules/
临时缓存
编译产物

也放进 stash,导致内容很乱。

更常用的是:

复制代码
git stash push -u -m "说明"

16. stash 可能产生冲突

恢复 stash 时也可能冲突。

例如:

复制代码
你 stash 了一份 readme.md 修改。
后来当前分支上的 readme.md 也变了。
再执行 git stash pop 时,两边改到了同一处。

Git 可能提示:

复制代码
CONFLICT (content): Merge conflict in readme.md

这时处理方式和 merge 冲突类似:

复制代码
git status

# 手动解决冲突

git add readme.md

如果是 git stash pop 发生冲突,Git 通常不会自动删除那条 stash。

这是为了防止你丢失数据。

解决完成后,你可以确认 stash 是否还在:

复制代码
git stash list

如果确认不需要了,再删除:

复制代码
git stash drop stash@{0}

17. stash 的推荐工作流

当你正在开发,突然需要切分支:

复制代码
git status
git diff
git stash push -u -m "临时保存登录功能开发"
git status
git switch master

如果主分支叫 main

复制代码
git switch main

处理完紧急事情后,回到功能分支:

复制代码
git switch feature/login
git stash list
git stash show -p stash@{0}
git stash apply stash@{0}

确认恢复正常后:

复制代码
git stash drop stash@{0}

这个流程比较稳妥。

18. Gerrit 工作流中的 stash

Gerrit 中常见场景:

复制代码
你正在修改 Review 意见。
突然需要同步目标分支。
但是工作区还有未完成修改,不能直接 rebase。

这时可以:

复制代码
git status
git stash push -u -m "临时保存 review 修改"
git fetch origin
git rebase origin/master
git stash pop

如果目标分支是 develop

复制代码
git fetch origin
git rebase origin/develop
git stash pop

恢复后继续修改,最后:

复制代码
git add .
git commit --amend --no-edit
git push origin HEAD:refs/for/master

19. stash 和 commit 的选择

很多新手会问:

复制代码
什么时候用 stash?
什么时候用 commit?

可以这样判断:

场景 推荐
修改还没完成,只是临时保存 stash
修改已经形成一个清楚阶段 commit
需要和别人共享 commit 后 push
只是切分支前临时收起 stash
代码有明确意义,需要历史记录 commit

简单记忆:

复制代码
stash 是临时收纳。
commit 是正式记录。

20. 实战练习一:基础 stash

创建练习仓库:

复制代码
mkdir git-stash-demo
cd git-stash-demo
git init

创建初始提交:

复制代码
echo "base" > readme.txt
git add readme.txt
git commit -m "添加基础文件"

修改文件但不提交:

复制代码
echo "work in progress" >> readme.txt
git status

临时保存:

复制代码
git stash push -m "临时保存 readme 修改"

查看状态:

复制代码
git status

查看 stash:

复制代码
git stash list
git stash show -p stash@{0}

恢复:

复制代码
git stash pop

再次查看状态:

复制代码
git status

21. 实战练习二:保存未跟踪文件

新建文件:

复制代码
echo "new file" > new-file.txt
git status

你会看到:

复制代码
Untracked files:
  new-file.txt

保存包含新文件的修改:

复制代码
git stash push -u -m "保存新文件"

查看状态:

复制代码
git status

恢复:

复制代码
git stash pop

你会看到 new-file.txt 回来了。

22. 实战练习三:apply 和 drop

修改文件:

复制代码
echo "apply test" >> readme.txt
git stash push -m "测试 apply"

查看 stash:

复制代码
git stash list

使用 apply:

复制代码
git stash apply stash@{0}

再次查看 stash:

复制代码
git stash list

你会发现:

复制代码
stash 仍然存在。

确认不需要后删除:

复制代码
git stash drop stash@{0}

23. 实战练习四:模拟紧急修复

创建功能分支:

复制代码
git switch -c feature/login

写到一半:

复制代码
echo "login half done" > login.txt
git status

现在假设要紧急修复主分支 bug。

先 stash:

复制代码
git stash push -u -m "临时保存登录功能半成品"

切回主分支:

复制代码
git switch main

如果主分支叫 master

复制代码
git switch master

创建修复分支:

复制代码
git switch -c hotfix/readme

修复并提交:

复制代码
echo "hotfix" >> readme.txt
git add readme.txt
git commit -m "修复 readme 问题"

回到原功能分支:

复制代码
git switch feature/login
git stash list
git stash pop

继续开发。

24. 常见错误

错误一:长期把代码放在 stash 里

stash 是临时工具,不是长期仓库。

如果修改很重要,应该尽快整理成 commit。

错误二:stash 太多但没有说明

不要一直使用:

复制代码
git stash

更推荐:

复制代码
git stash push -m "清楚说明"

错误三:恢复错 stash

恢复前先看:

复制代码
git stash list
git stash show -p stash@{0}

确认内容后再恢复。

错误四:忘记 -u 导致新文件没保存

如果有未跟踪文件,使用:

复制代码
git stash push -u -m "说明"

错误五:随便执行 git stash clear

git stash clear 会删除所有 stash。

新手不要随便用。

错误六:stash pop 冲突后不知道怎么办

冲突后:

复制代码
git status
# 手动解决冲突
git add 冲突文件

然后确认 stash 是否还在:

复制代码
git stash list

25. 本节必须记住的命令

复制代码
git stash push -m "说明"
git stash push -u -m "说明"
git stash list
git stash show -p stash@{0}
git stash pop
git stash apply stash@{0}
git stash drop stash@{0}
git stash clear

对应含义:

复制代码
git stash push -m "说明"          临时保存已跟踪文件修改
git stash push -u -m "说明"       临时保存修改,包括未跟踪文件
git stash list                    查看 stash 列表
git stash show -p stash@{0}       查看 stash 具体内容
git stash pop                     恢复最新 stash 并删除记录
git stash apply stash@{0}         恢复指定 stash 但保留记录
git stash drop stash@{0}          删除指定 stash
git stash clear                   清空所有 stash

26. 本节总结

这一节你学习了 stash

  • stash 用来临时保存未提交修改

  • stash 适合切分支、rebase、pull 前临时清理工作区

  • git stash pop 会恢复并删除 stash

  • git stash apply 会恢复但保留 stash

  • git stash push -u 可以包含未跟踪文件

  • 恢复 stash 也可能产生冲突

  • stash 是临时收纳,不是正式历史

最重要的一句话:

复制代码
stash 用来临时保护未完成代码,commit 才是正式保存开发历史。

下一节建议学习:

复制代码
Git reset 与 revert:如何撤销提交,以及为什么团队协作中更推荐 revert。
相关推荐
enjoywindstorm2 小时前
git从入门到精通
git
Adorable老犀牛6 小时前
Git 发布正式版本的一个专属的硬核功能,叫做 打标签(Tag)。
git
我先去打把游戏先7 小时前
Ubuntu虚拟机(服务器版本)Git卸载完全教程——彻底移除与清理配置
服务器·git·单片机·嵌入式硬件·物联网·ubuntu·51单片机
不做无法实现的梦~9 小时前
Git Clone 使用 Watt/Steam++ 加速时报证书错误的原因与解决方法
大数据·git·elasticsearch
黑猫警长丶10 小时前
Git 操作笔记
笔记·git
MageGojo10 小时前
Whois 域名查询 API 接入实战:用一个 GET 请求获取域名注册信息
java·git·github
黑猫警长丶10 小时前
Git 本地操作基础
git
白狐_79810 小时前
从功能开发到开源维护:一个 Python 可视化项目的 Git 分支、维护文件与 PR 流程实践
git·python·开源
思麟呀11 小时前
git分支
git