Git 完全指南 / 06 - 暂存:stash、stash pop、stash branch
第六章:暂存(Stash)
Stash 让你快速保存和恢复工作现场,是紧急切换分支时的救星。
6.1 暂存概述
当你正在开发某个功能,突然需要切换分支处理紧急 bug 时,git stash 可以快速保存当前工作区和暂存区的状态,让你的工作区恢复干净。
工作区状态 → git stash → 干净工作区 → 切换分支 → 处理任务 → 切回 → git stash pop → 恢复工作
6.2 基本操作
6.2.1 保存暂存
# 暂存已跟踪文件的修改(默认)
$ git stash
# 等价于
$ git stash push
# 暂存并添加描述信息
$ git stash push -m "正在开发登录功能"
# 暂存所有文件(包括未追踪文件)
$ git stash push -u
# 或
$ git stash push --include-untracked
# 暂存所有文件(包括忽略文件)
$ git stash push -a
# 或
$ git stash push --all
# 只暂存指定文件
$ git stash push -m "部分暂存" -- src/login.js src/auth.js
# 暂存时包含暂存区状态
$ git stash push --staged
6.2.2 查看暂存列表
# 查看暂存列表
$ git stash list
stash@{0}: WIP on main: abc1234 Add feature
stash@{1}: WIP on develop: def5678 Fix bug
stash@{2}: On main: 正在开发登录功能
# 格式化输出
$ git stash list --format="%gd: %gs (%cr)"
stash@{0}: WIP on main: abc1234 (2 minutes ago)
stash@{1}: WIP on develop: def5678 (1 hour ago)
6.2.3 恢复暂存
# 恢复最近的暂存并从列表移除
$ git stash pop
# 或
$ git stash pop stash@{0}
# 恢复暂存但保留在列表中
$ git stash apply
# 或
$ git stash apply stash@{0}
# 恢复指定的暂存
$ git stash pop stash@{2}
pop vs apply 对比:
| 操作 | 恢复内容 | 从列表移除 | 适用场景 |
|---|---|---|---|
stash pop | ✅ | ✅ | 确认不再需要此暂存 |
stash apply | ✅ | ❌ | 需要多次应用同一暂存 |
6.2.4 删除暂存
# 删除最近的暂存
$ git stash drop
# 删除指定暂存
$ git stash drop stash@{1}
# 清除所有暂存
$ git stash clear
6.2.5 查看暂存内容
# 查看暂存的变更摘要
$ git stash show
# 查看暂存的详细差异
$ git stash show -p
# 查看指定暂存的差异
$ git stash show -p stash@{1}
# 只显示文件名
$ git stash show --name-only
6.3 高级用法
6.3.1 从暂存创建分支
当你恢复暂存时遇到冲突,可以用 stash branch 创建一个新分支来恢复:
# 基于暂存时的提交创建新分支并恢复暂存
$ git stash branch feature-from-stash
Switched to a new branch 'feature-from-stash'
On branch feature-from-stash
Changes not staged for commit:
modified: src/app.js
# 基于指定暂存创建分支
$ git stash branch fix-from-stash stash@{2}
💡 这是解决 stash pop 冲突的最佳方式。
6.3.2 交互式暂存
# 交互式选择要暂存的内容
$ git stash push -p
# 会像 git add -p 一样逐块询问
diff --git a/src/app.js b/src/app.js
...
Stash this hunk [y,n,q,a,d,s,e,?]?
6.3.3 保留暂存区状态
# 暂存时保留暂存区(index)的状态
$ git stash push --staged
# 恢复后暂存区状态也会恢复
$ git stash pop
6.3.4 暂存未追踪文件
# 默认只暂存已追踪文件的修改
$ git stash
# 包含未追踪的新文件
$ git stash -u
# 包含被 .gitignore 忽略的文件
$ git stash -a
# 注意:-a 包含所有文件,可能暂存不应提交的内容
6.4 暂存内部机制
暂存本质上是一个特殊的提交:
# 查看暂存的提交对象
$ git stash list --format="%H %s"
abc1234def567890 WIP on main: ghi9012 Latest commit
# 查看暂存的对象类型
$ git cat-file -t abc1234
commit
# 查看暂存的提交内容
$ git cat-file -p abc1234
tree def5678...
parent ghi9012...
author ...
committer ...
WIP on main: ghi9012 Latest commit
暂存实际创建了 2-3 个提交:
- 工作区提交:包含未暂存的修改
- 暂存区提交:包含
git add后的内容 - 未追踪文件提交(如果使用
-u或-a)
6.5 常见问题与解决
6.5.1 Stash Pop 冲突
$ git stash pop
Auto-merging src/app.js
CONFLICT (content): Merge conflict in src/app.js
The stash entry is kept in case you need it again.
解决方法:
# 方法 1:手动解决冲突
$ vim src/app.js # 编辑冲突
$ git add src/app.js
$ git stash drop # 删除已应用的暂存
# 方法 2:创建新分支恢复(推荐)
$ git stash branch temp-fix-branch
6.5.2 暂存丢失恢复
如果不小心执行了 git stash clear:
# 使用 fsck 查找悬空对象
$ git fsck --unreachable | grep commit
dangling commit abc1234...
# 查看悬空提交内容
$ git show abc1234
# 恢复
$ git stash apply abc1234
6.6 暂存命令速查表
| 命令 | 说明 |
|---|---|
git stash | 暂存已跟踪文件的修改 |
git stash push -m "msg" | 暂存并添加描述 |
git stash -u | 包含未追踪文件 |
git stash -a | 包含所有文件 |
git stash list | 查看暂存列表 |
git stash show | 查看暂存摘要 |
git stash show -p | 查看暂存详细差异 |
git stash pop | 恢复并删除暂存 |
git stash apply | 恢复但保留暂存 |
git stash branch <name> | 创建分支并恢复 |
git stash drop | 删除暂存 |
git stash clear | 清除所有暂存 |
git stash push -p | 交互式暂存 |
业务场景
| 场景 | 推荐方案 |
|---|---|
| 紧急切换分支修 bug | git stash -u → 切分支 → 修 bug → 切回 → git stash pop |
| 尝试不同实现 | git stash push -m "方案A" → 尝试方案 B → 对比选择 |
| 拉取远程更新 | git stash → git pull → git stash pop |
| 保留临时实验代码 | git stash push -m "实验性代码" 长期保留 |
| 代码审查中途 | git stash → 处理其他事务 → git stash pop 继续 |