Skip to content

储藏(Stash)

git stash 是一个临时保存工作区和暂存区状态的工具。当你需要切换分支处理紧急任务,但当前工作还没完成时,stash 可以帮你"搁置"当前进度。

git stash / git stash push

bash
# 储藏当前所有改动(包括已暂存和未暂存的已跟踪文件)
git stash
git stash push    # 等价,更明确

# 储藏后工作区恢复干净状态
git status
# nothing to commit, working tree clean

git stash -m 带描述储藏

bash
# 带描述信息储藏(推荐,方便后续识别)
git stash push -m "feat: 用户登录功能进行到一半"
git stash -m "修复中途被打断"

# 带描述的 stash list 显示
git stash list
# stash@{0}: On main: 修复中途被打断
# stash@{1}: On feature/login: feat: 用户登录功能进行到一半

git stash list 查看列表

bash
git stash list

# 输出:
# stash@{0}: WIP on main: abc123 feat: 最新提交      ← 最新的 stash
# stash@{1}: On feature/login: 用户登录功能进行到一半
# stash@{2}: WIP on develop: def456 fix: 修复样式

# 显示每个 stash 的改动统计
git stash list --stat

# 显示 stash 的完整差异
git stash show -p stash@{0}

# 查看某个 stash 的内容摘要
git stash show stash@{1}

git stash pop vs git stash apply

bash
# pop:恢复并删除最新的 stash(推荐)
git stash pop

# pop 指定的 stash
git stash pop stash@{2}

# apply:恢复但不删除 stash(stash 仍然保留)
git stash apply
git stash apply stash@{1}

# 恢复时同时恢复暂存区状态(默认 apply 不恢复暂存区)
git stash pop --index
git stash apply --index

pop vs apply:

命令恢复 stash删除 stash
pop
apply❌(stash 仍保留)

git stash drop / git stash clear

bash
# 删除最新的 stash
git stash drop

# 删除指定 stash
git stash drop stash@{2}

# 删除所有 stash
git stash clear

git stash branch 从储藏创建分支

当 stash 的内容与当前代码冲突时,可以将 stash 创建为新分支:

bash
# 从 stash 创建新分支(恢复 stash 时基于 stash 创建时的提交)
git stash branch feature/stashed-work

# 指定 stash
git stash branch fix/saved-work stash@{2}

这相当于:

  1. 创建新分支(基于 stash 储藏时的提交)
  2. 在新分支上应用 stash
  3. 删除 stash

git stash -p 交互式储藏

选择性地储藏部分改动(类似 git add -p):

bash
git stash -p
git stash push -p   # 等价

# 会显示每个 hunk,提示操作:
# Stash this hunk [y,n,q,a,d,/,e,?]?
# y - 储藏此块
# n - 不储藏此块(保留在工作区)
# q - 退出
# a - 储藏此文件的所有块
# ...

git stash --include-untracked 包含未跟踪文件

默认情况下,git stash 不储藏未跟踪的文件(新建但未 git add 的文件):

bash
# 包含未跟踪文件
git stash --include-untracked
git stash -u    # 简写

# 包含未跟踪文件和被 .gitignore 忽略的文件
git stash --all
git stash -a    # 简写(谨慎使用,会储藏 .gitignore 的文件)

实际使用场景

场景1:紧急切换分支

bash
# 正在 feature 分支上开发,突然需要修复线上 bug
git stash push -m "feat: 用户登录功能-进行到认证逻辑部分"

# 切换到 main 修复 bug
git switch main
git switch -c hotfix/urgent-bug
# 修复 bug...
git commit -m "fix: 修复用户无法登录的问题"
git switch main
git merge hotfix/urgent-bug
git push

# 回到功能开发
git switch feature/user-login
git stash pop

场景2:提交前临时保存测试代码

bash
# 添加了一些临时调试代码
git stash push -m "临时调试代码(不提交)"

# 提交正式的改动
git add .
git commit -m "feat: 添加用户头像功能"

# 恢复调试代码继续调试
git stash pop

场景3:在错误分支上开发了代码

bash
# 发现在 main 分支上开发了功能(应该在 feature 分支)
git stash

# 创建并切换到正确的分支
git switch -c feature/new-feature

# 恢复代码到新分支
git stash pop

场景4:测试 stash 内容是否适用于当前分支

bash
# 先预览 stash 的内容
git stash show -p stash@{0}

# 在新分支上试验
git stash branch trial-branch stash@{0}
# 如果不合适,直接删除这个分支

stash 的存储结构

每个 stash 实际上是一个特殊的 commit 对象:

bash
# 查看 stash 的详细信息
git cat-file -p stash@{0}
# 包含三个父提交:
# 1. 储藏时的 HEAD(当前提交)
# 2. 暂存区内容(作为 commit)
# 3. 未跟踪文件(如果有 -u)

总结

操作命令
储藏当前改动git stash push -m "描述"
查看 stash 列表git stash list
恢复并删除git stash pop
只恢复不删除git stash apply
删除 stashgit stash drop stash@{n}
清空所有 stashgit stash clear
从 stash 创建分支git stash branch <name>
包含未跟踪文件git stash -u
交互式储藏git stash -p

Stash 是处理工作中断的利器,但不要把它当作长期存储的工具。对于需要长期保存的工作进度,应该创建一个 WIP(Work In Progress)提交或分支。