Docs Library

Git Stash 概念:临时保存工作上下文

系统解释 git stash 的概念——它是什么、什么时候用、有什么限制,以及如何安全地管理临时保存的工作上下文。

适合谁看
  • 想先理解历史图再看命令的人
前置知识
  • 知道提交不是文件快照列表那么简单
常见风险
  • 把概念页当命令说明页使用

一句话理解

Git stash 是一个临时存储区,用来暂存当前工作区中还没准备好提交的改动,让你可以切换去做其他事情,之后再回来恢复。

为什么需要 Stash

在日常开发中,经常遇到这样的场景:

你在 feature/login 分支上写代码,写到一半突然需要切到另一个分支修一个紧急 bug。但你的改动还没完成,不适合提交。

此时你有几个选择:

方案优点缺点
直接提交半成品快速污染提交历史
创建一个临时分支结构清晰操作步骤多
git stash快速、无副作用需理解其限制

git stash 是最低成本的方案——它把你的工作区改动暂存到栈里,让工作区恢复干净,以后随时可以恢复。

Stash 的本质

Stash 实际上是两个特殊的提交——工作区内容的提交和暂存区内容的提交,都基于 stash 创建时的 HEAD。

Stash 的工作流程工作区改动通过 git stash 保存到 stash 栈,之后通过 git stash pop/apply 恢复。stash 实例可同时保存工作区和暂存区的状态。
工作区edited files
git stash save
Stash 栈stash@{0} / stash@{1}
git stash pop
恢复的工作区resume work

当你执行 git stash 时,Git 会:

  1. 把当前的暂存区内容保存为一个 commit(index commit)
  2. 把当前的工作区内容保存为一个 commit(worktree commit)
  3. 把这两个 commit 作为一个特殊的 stash 引用

使用 git stash list 看到的就是这个栈的内容。

核心操作

保存到 stash

# 暂存已跟踪文件的改动(默认)
git stash

# 包含未跟踪文件
git stash push -u

# 包含忽略文件
git stash push -a

# 添加描述信息
git stash push -m "WIP: login form validation"

查看 stash

# 列出所有 stash
git stash list

# 查看某个 stash 的改动
git stash show stash@{0}

# 查看某个 stash 的详细 diff
git stash show -p stash@{0}

恢复 stash

# 恢复并移除栈顶 stash(pop)
git stash pop

# 恢复但不移除(apply)
git stash apply stash@{1}

# 恢复并恢复暂存区状态
git stash apply --index

清理 stash

# 移除栈顶
git stash drop

# 移除指定 stash
git stash drop stash@{0}

# 清空所有 stash
git stash clear
Stash 不等于备份

Stash 默认只保存已跟踪文件的改动,未跟踪文件需要用 -u 参数。它不是永久存储——git stash dropgit stash clear 会彻底删除条目。跨分支恢复 stash 也可能产生冲突。建议每个 stash 都加描述信息(-m),恢复时优先用 pop 而不是 apply,避免栈堆积。

Stash 的重要限制

1. 默认只跟踪已跟踪文件

# 新文件不会被 stash 保存
git stash      # 不会保存新创建的 untracked 文件

# 需要用 -u 或 --include-untracked
git stash -u   # 会保存 untracked 文件

2. 不跟踪文件模式变化

Git stash 在默认配置下不保存文件的可执行权限变化。

3. 恢复时可能产生冲突

当 stash 中的改动和当前工作区冲突时,恢复 stash 会产生冲突,需要手动解决。

4. 跨分支恢复需谨慎

跨分支恢复 stash 时,如果文件结构差异较大,恢复结果可能出乎意料。

5. 不是永久存储

Stash 存储在 .git/refs/stash 中。虽然不会主动过期,但如果通过 git stash dropgit stash clear 删除,就没有恢复途径。

常见使用模式

模式一:快速切任务

# 保存当前工作
git stash push -m "WIP: login validation"

# 切到其他分支修 bug
git switch hotfix
# ... 修复并提交 ...

# 切回来恢复工作
git switch feature/login
git stash pop

模式二:保留暂存区状态

# 暂存了一些文件,想保留暂存状态
git add src/login.ts src/utils.ts

# 保存时保留暂存区
git stash push --staged

# 或者使用 --index 保持恢复后的暂存状态
git stash apply --index

模式三:拆分混乱的改动

# 想把当前的混乱改动拆成多个 stash
git stash push -m "part 1: login logic"

# 恢复前先清理工作区
git stash push -m "part 2: test updates"

模式四:创建分支从 stash 恢复

当 stash 冲突太多难以恢复时:

# 从 stash 创建新分支
git stash branch new-feature stash@{0}

Stash 栈管理

控制栈大小

Stash 是一个栈结构(LIFO),新的 stash 在栈顶:

stash@{0}  ← 最新
stash@{1}
stash@{2}  ← 最旧

长时间不清理会堆积大量 stash,导致:

  • 上下文难以追踪
  • 容易误操作旧 stash
  • 占用不必要的存储空间

建议的清理策略

  • 每个 stash 都加描述信息(-m
  • 恢复后立即删除(使用 pop 而不是 apply
  • 每周清理一次无用 stash
  • stash 数量控制在 5 个以内

高级技巧

使用场景指定 stash

# 只暂存工作区中已跟踪文件的某部分
git stash push -p

# 在 stash 中只暂存暂存区
git stash push --staged

# 从 stash 中恢复特定文件
git checkout stash@{0} -- src/login.ts

使用 reflog 找回误删的 stash

如果不小心 git stash clear,只要对象还没被 GC 回收,可以用 reflog 找回:

# 在 clear 后立即查找
git fsck --unreachable | grep commit | cut -d ' ' -f3

# 检查找到的提交
git show <commit-hash>

继续学习建议

理解 stash 概念后,建议继续学习:

  1. git stash 命令的完整参数
  2. git stash vs git worktree 的选择
  3. recovery/recover-lost-stash —— 丢失 stash 后如何恢复
  4. stashgit rebasegit merge 中的交互