搜索 K
主题
git stash 是 Git 中用于临时保存未提交修改的命令。它会将工作区和暂存区的修改保存到一个栈结构中,让工作区恢复到干净状态,方便你切换分支、拉取更新或处理紧急任务。之后可以随时恢复这些修改。
git stash 就像一个「剪贴板栈」——你可以随时把当前的修改「剪切」走,处理完其他事情后再「粘贴」回来。
git stash [push [-p] [-S] [-k] [-u | -a] [-m <message>] [-- <pathspec>…]]
git stash list
git stash show [<stash>]
git stash pop [<stash>]
git stash apply [<stash>]
git stash drop [<stash>]
git stash clear
git stash branch <branchname> [<stash>]git stash 实际上会创建两到三个特殊的提交对象来保存当前状态:
git add 过的修改)-u 或 -a 时)stash 使用后进先出(LIFO)的栈结构管理多个存储:
stash@{N} 中 N 是从 0 开始的索引,0 表示最新的 stash。每次新增 stash 时,旧的索引会自动 +1。
git stash(快速保存) 最简单的用法,保存所有已跟踪文件的修改(包括暂存和未暂存的):
# 快速保存(等价于 git stash push)
git stash
# 带描述信息(强烈推荐)
git stash push -m "feat: 用户登录页面半成品"
# 简写形式
git stash -m "WIP: 重构认证模块"养成使用 -m 添加描述的习惯。没有描述的 stash 在 git stash list 中只会显示基于分支名和提交信息的默认标题,时间久了完全记不住每个 stash 保存了什么。
默认情况下,git stash 不会保存未跟踪文件(新建但未 git add 过的文件)和被忽略的文件。
# 包含未跟踪文件(untracked files)
git stash push -u
git stash push --include-untracked
# 包含所有文件(含 .gitignore 中的文件)
git stash push -a
git stash push --all-a 慎用git stash -a 会保存 .gitignore 中的文件(如 node_modules/、build/),可能导致 stash 体积非常大。通常 -u 就够了。
# 只保存指定文件
git stash push -m "保存配置文件" -- src/config.ts .env
# 只保存某个目录
git stash push -m "保存 API 模块" -- src/api/
# 交互式选择要保存的代码块
git stash push -p--keep-index:保留暂存区 # 保存工作区修改,但保留暂存区不变
git stash push --keep-index
# 简写
git stash push -k--keep-index 的使用场景当你已经 git add 了一部分文件准备提交,但想先测试暂存区中的代码是否能正常工作:
git add src/feature.ts
git stash push -k -m "暂存工作区其余修改"
# 此时工作区只有已暂存的文件,可以运行测试
npm test
# 测试通过后恢复其余修改
git stash pop--staged:只保存暂存区(Git 2.35+) # 只保存已暂存的修改,工作区未暂存的修改保持不变
git stash push --staged
git stash push -S--staged vs --keep-index| 参数 | 保存到 stash 的内容 | 工作区状态 |
|---|---|---|
--keep-index | 暂存 + 未暂存的修改 | 只保留暂存区的修改 |
--staged | 只保存暂存区的修改 | 暂存区清空,未暂存修改保持不变 |
git stash list
# stash@{0}: On main: feat: 用户登录页面半成品
# stash@{1}: On develop: WIP: 重构认证模块
# stash@{2}: On main: WIP on main: abc1234 初始化项目# 查看最新 stash 的文件变更摘要
git stash show
# src/auth.ts | 15 ++++++++++++---
# src/api.ts | 8 +++++---
# 2 files changed, 17 insertions(+), 6 deletions(-)
# 查看详细 diff
git stash show -p
# 查看指定 stash 的内容
git stash show -p stash@{2}
# 只查看文件名
git stash show --name-only
# 查看 stash 中的指定文件
git stash show -p stash@{0} -- src/auth.tspop vs apply | 命令 | 恢复修改 | 删除 stash | 适用场景 |
|---|---|---|---|
git stash pop | ✅ | ✅ | 只需要恢复一次(最常用) |
git stash apply | ✅ | ❌ | 想在多个分支上应用同一个 stash |
# 恢复最新的 stash 并从栈中删除
git stash pop
# 恢复最新的 stash 但保留在栈中
git stash apply
# 恢复指定的 stash
git stash pop stash@{2}
git stash apply stash@{2}默认情况下,pop 和 apply 会将所有修改都放到工作区(未暂存状态),即使某些修改之前是已暂存的。
# 恢复时保留原始的暂存状态
git stash pop --index
git stash apply --index--index 的重要性如果你在 stash 前精心安排了暂存区(部分文件已 git add),恢复时务必加 --index,否则所有修改都会变成未暂存状态,你的暂存工作白费了。
如果 stash 恢复时工作区已有修改,或分支已发生变化,可能产生冲突:
# 恢复 stash
git stash pop
# CONFLICT (content): Merge conflict in src/main.ts
# 手动解决冲突后
git add src/main.ts
# 注意:pop 冲突时不会自动删除 stash
# 需要手动删除
git stash drop如果 git stash pop 遇到冲突,stash 不会被自动删除(与成功 pop 时不同)。解决冲突后需要手动 git stash drop 清理。
# 删除最新的 stash
git stash drop
# 删除指定的 stash
git stash drop stash@{2}
# 清空所有 stash(不可逆!)
git stash cleargit stash clear 不可逆清空后的 stash 无法通过常规方式找回。虽然理论上可以用 git fsck --lost-found 尝试恢复,但不保证成功。
git stash branch 会基于创建 stash 时的提交创建新分支,并自动应用 stash:
# 从最新 stash 创建新分支
git stash branch feature-from-stash
# 从指定 stash 创建新分支
git stash branch fix/hotfix stash@{2}stash branch最适合以下场景:
pop 会产生冲突pop 冲突后,想换个干净的环境恢复 stash# 正在 feature 分支开发,突然需要修复线上 bug
git stash push -m "WIP: feature-x 开发中"
# 切到 main 修复 bug
git checkout main
git checkout -b hotfix/urgent-bug
# ... 修复并提交 ...
git checkout main
git merge hotfix/urgent-bug
git push
# 回到 feature 继续开发
git checkout feature-x
git stash pop# 本地有未提交的修改,直接 pull 会被拒绝
git stash push -m "拉取前备份"
git pull --rebase origin main
git stash pop
# 如果 pop 有冲突,解决后:
git add .
git stash drop# 保存不同功能的修改到不同 stash
git stash push -m "feat: 用户页面" -- src/pages/user/
git stash push -m "feat: API 模块" -- src/api/
# 查看所有 stash
git stash list
# stash@{0}: On main: feat: API 模块
# stash@{1}: On main: feat: 用户页面
# 恢复指定的 stash(注意索引)
git stash pop stash@{1} # 恢复用户页面# 已暂存了部分修改准备提交
git add src/feature.ts src/test.ts
# 暂存其余修改,只保留暂存区用于测试
git stash push -k -m "临时隐藏未暂存修改"
# 运行测试
npm test
# 测试通过 → 提交
git commit -m "feat: 新功能"
# 恢复其余修改
git stash pop# 不小心在 main 上提交了,想移到 feature 分支
git reset --soft HEAD~2
git stash push -m "移动到 feature 分支的修改"
git checkout -b feature-branch
git stash pop
git commit -m "feat: 正确的功能提交"# 新建了 .env.local,还没 add,但需要保留
git stash push -u -m "包含本地配置文件"
# 恢复时未跟踪文件也会恢复
git stash pop收到同事的 PR 审查请求,需要切到他的分支测试,但自己手上有未完成的工作:
# 1. 保存当前工作
git stash push -u -m "WIP: 正在开发的订单模块"
# 2. 拉取并切到同事的分支
git fetch origin
git checkout pr/feature-auth
# 3. 审查代码、运行测试
npm test
# ... 写审查意见 ...
# 4. 回到自己的分支继续工作
git checkout feature-order
git stash pop当不确定 bug 是来自自己的修改还是已有代码时,stash 可以快速隔离:
# 当前工作区有大量修改,出现了 bug
# 问题:bug 是我的修改引入的,还是之前就有?
# 1. 保存所有修改
git stash push -u -m "debug: 隔离测试"
# 2. 在干净的代码上运行测试
npm test
# 如果测试通过 → bug 是你的修改引入的
# 如果测试失败 → bug 在之前的代码中
# 3. 恢复修改
git stash pop
# 4. 如果是自己的修改导致的,可以用 -p 逐步恢复
git stash push -u -m "debug: 全部修改"
git stash pop --index # 先恢复全部
# 或者用 -p 交互式恢复,逐块确认开发进行到一半,突然接到线上紧急 bug 报告:
当你需要在多个功能之间频繁切换时,stash 栈可以像「多个剪贴板」一样使用:
# 任务 A:开发支付模块
git stash push -m "task-A: 支付模块 - 完成了 checkout 逻辑"
# 切换到任务 B
git checkout feature-b
# ... 工作一段时间 ...
git stash push -m "task-B: 用户设置 - 完成了表单验证"
# 切换到任务 C
git checkout feature-c
# ... 紧急修复 ...
git commit -m "fix: 修复紧急问题"
# 回到任务 A
git checkout feature-a
git stash list
# stash@{0}: On feature-b: task-B: 用户设置 - 完成了表单验证
# stash@{1}: On feature-a: task-A: 支付模块 - 完成了 checkout 逻辑
git stash pop "stash@{1}" # 恢复任务 A 的修改如果修改需要保存超过几个小时,建议创建 WIP 提交而非 stash:
# WIP 提交(更持久、更安全)
git add .
git commit -m "WIP: 支付模块开发中(未完成)"
# 后续继续开发时
git reset --soft HEAD~1 # 取消 WIP 提交,保留修改因为 stash 是纯本地的——不会被 push,也不会被 clone,换电脑就丢了。
对比修改前后的性能差异:
# 1. 记录修改后的性能
node benchmark.js
# Result: 1200ms
# 2. stash 所有修改
git stash push -m "性能优化修改"
# 3. 测试原始代码的性能
node benchmark.js
# Result: 1800ms
# 4. 恢复修改
git stash pop
# 结论:优化提升了 33% 性能git worktree 避免频繁切换 如果你需要同时在多个分支上工作,git worktree 比反复 stash + checkout 更高效:
# 传统方式:stash → checkout → pop → ... → stash → checkout → pop
# 每次切换都要 stash/pop,很烦
# 更好的方式:使用 worktree 创建多个工作目录
git worktree add ../project-hotfix hotfix/urgent
git worktree add ../project-feature feature-x
# 现在你可以在不同终端/编辑器窗口中同时编辑不同分支
# 完全不需要 stash!
# 清理
git worktree remove ../project-hotfix| 场景 | 推荐方式 |
|---|---|
| 临时切换分支(< 30 分钟) | stash |
| 长时间并行开发多个功能 | worktree |
| 临时查看某个分支的代码 | stash |
| 同时运行多个分支的服务 | worktree |
| CI/CD 脚本中临时保存状态 | stash |
在团队中或自己管理多个 stash 时,使用一致的命名规范:
# 推荐的命名格式:[类型]: [简述] - [状态]
git stash push -m "feat: 支付模块 - 完成 70%"
git stash push -m "fix: 登录验证 bug - 待测试"
git stash push -m "debug: 隔离性能问题"
git stash push -m "backup: reset 前的完整备份"
git stash push -m "review: PR#456 审查前保存"如果需要将 stash 分享给同事或跨仓库应用:
# 导出 stash 为 patch 文件
git stash show -p stash@{0} > my-changes.patch
# 在另一个仓库/机器上应用
git apply my-changes.patch
# 或发送给同事
# 同事执行:git apply my-changes.patch# 查看 stash 中某个文件的完整内容(不是 diff)
git show stash@{0}:src/config.ts
# 只从 stash 中恢复特定文件(不影响其他修改)
git checkout stash@{0} -- src/config.ts
# 查看 stash 中哪些文件被修改了
git stash show --name-only stash@{0}
# 对比 stash 内容和当前工作区
git diff stash@{0}# 在 ~/.gitconfig 中添加
[alias]
# 快速 stash(带描述)
ss = stash push -m
# stash 含未跟踪文件
ssu = stash push -u -m
# 查看 stash 列表
sl = stash list
# 查看最新 stash 的详细内容
sd = stash show -p
# 恢复最新 stash
sp = stash pop
# 恢复但保留
sa = stash apply
# 使用
git ss "WIP: 开发中" # 快速保存
git ssu "含新文件的修改" # 含未跟踪文件
git sl # 查看列表
git sd # 查看内容
git sp # 恢复# 查看所有 stash 的创建时间
git stash list --date=relative
# stash@{0}: 2 hours ago: On main: WIP
# stash@{1}: 3 days ago: On feature: 旧的修改
# stash@{2}: 2 weeks ago: On develop: 已经不需要了
# 逐个检查内容后决定是否删除
git stash show -p stash@{2}
git stash drop stash@{2}
# 或者一次性清理所有(确认不需要后)
git stash clear建议每周检查一次 stash 列表。超过一周的 stash 通常已经不需要了——如果需要,应该已经创建了正式的提交或分支。
最常见的问题不是 stash 丢失,而是忘记自己 stash 过东西。几天后发现代码不见了,以为丢失了:
# 养成习惯:每次 stash 后检查列表
git stash
git stash list # 确认保存成功
# 切换分支前也检查
git stash list # 有没有未恢复的 stash?stash pop 会应用到当前分支,不是创建 stash 时的分支:
# 在 feature-a 上 stash
git checkout feature-a
git stash push -m "feature-a 的修改"
# 忘记切回来,直接在 main 上 pop
git checkout main
git stash pop # ⚠️ feature-a 的修改被应用到了 main 上!
# 补救:如果还没有 add/commit
git stash # 重新 stash
git checkout feature-a
git stash pop # 在正确的分支上恢复stash 栈积压了太多条目,分不清哪个是哪个:
git stash list
# stash@{0}: WIP on main: abc1234 fix something
# stash@{1}: WIP on main: def5678 fix something
# stash@{2}: WIP on develop: ghi9012 init
# ... 20 个没有描述的 stash ...
# 预防方法:
# 1. 始终使用 -m 添加描述
# 2. 及时 pop 或 drop
# 3. 长期修改用 WIP commit 而非 stash如果你的项目依赖 .env 文件或 node_modules,默认 stash 不会保存它们。切换分支后这些文件可能状态不对:
# 需要时显式包含
git stash push -u # 包含未跟踪文件
git stash push -a # 包含被忽略的文件(慎用,体积可能很大)git stash pop 会将修改应用到当前所在的分支,不一定是创建 stash 时的分支。这意味着你可以在分支 A 上 stash,然后在分支 B 上 pop。
如果分支差异太大导致冲突,考虑使用 git stash branch 创建新分支来恢复。
可以。使用 git stash apply(而非 pop)会保留 stash,你可以在不同分支上多次 apply:
git checkout branch-a
git stash apply stash@{0}
git checkout branch-b
git stash apply stash@{0}git stash 和 git stash push 有什么区别?在现代 Git 中,git stash 等价于 git stash push。push 是较新的子命令,支持更多选项(如 -- 指定路径、-S 只暂存 staged)。旧版本使用 git stash save,但 save 已被弃用。
# 推荐写法
git stash push -m "描述"
# 等价的简写
git stash -m "描述"
# 已弃用(不要用)
git stash save "描述".gitignore 中的文件吗?默认不会。需要使用 -a(--all)参数:
| 参数 | 已跟踪修改 | 未跟踪文件 | 被忽略文件 |
|---|---|---|---|
| 默认 | ✅ | ❌ | ❌ |
-u | ✅ | ✅ | ❌ |
-a | ✅ | ✅ | ✅ |
stash 条目的提交对象仍然可能存在于 Git 对象数据库中:
# 查找悬空的 stash 提交
git fsck --no-reflog | grep commit
# 查看可能是 stash 的提交
git show <sha>
# 如果确认是要恢复的 stash,应用它
git stash apply <sha>但这不保证成功——如果 git gc 已经运行过,对象可能已被清理。
git stash 在以下状态下无法使用:
必须先解决冲突或 abort 操作,才能 stash。
stash@{0} 报错?PowerShell 会将 @{} 解释为哈希表语法。解决方式:
# 方式 1:用引号包裹
git stash pop "stash@{0}"
# 方式 2:用反引号转义
git stash pop stash@`{0`}
# 方式 3:使用 Git Bashgit stash push -m "reset 前备份"
git reset --hard origin/main
# 如果需要恢复
git stash pop详见 Git reset
git stash push -m "rebase 前备份"
git rebase origin/main
git stash popgit stash
git checkout other-branch
# 查看完毕
git checkout original-branch
git stash pop| 目标 | 命令 |
|---|---|
| 快速保存 | git stash |
| 带描述保存 | git stash push -m "描述" |
| 含未跟踪文件 | git stash push -u |
| 含所有文件 | git stash push -a |
| 只保存指定文件 | git stash push -- <file> |
| 交互式保存 | git stash push -p |
| 保留暂存区 | git stash push -k |
| 只保存暂存区(2.35+) | git stash push -S |
| 查看列表 | git stash list |
| 查看内容 | git stash show -p [stash@{N}] |
| 恢复并删除 | git stash pop [stash@{N}] |
| 恢复但保留 | git stash apply [stash@{N}] |
| 恢复时保留暂存状态 | git stash pop --index |
| 删除指定 stash | git stash drop [stash@{N}] |
| 清空所有 stash | git stash clear |
| 从 stash 创建分支 | git stash branch <name> [stash@{N}] |
git clean — 删除未跟踪文件,功能与 stash -u 互补