本节目标
这一节学习 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 需要你马上修。
这时你想切换到 master 或 hotfix 分支。
但你的工作区还有未完成修改。
如果直接切分支,可能出现:
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。