Skip to content

储藏 (Stash)

概述

Git Stash 是一个强大的功能,允许你临时保存工作目录和暂存区的修改,而不需要提交它们。这在需要快速切换分支或处理紧急任务时非常有用。

什么是 Stash

Stash 就像一个临时储物柜,可以将当前的工作进度"藏起来",让工作目录恢复到干净的状态。当你处理完其他事情后,可以随时取回之前保存的工作进度。

Stash 的特点

  • 临时存储:保存未提交的修改
  • 栈结构:支持多个 Stash 记录
  • 跨分支:可以在不同分支间应用 Stash
  • 安全性:不会丢失工作进度

git stash 基本用法

创建 Stash

bash
# 基本用法:储藏当前修改
git stash

# 带描述信息的储藏
git stash save "描述信息"

# 推荐的新语法(Git 2.13+)
git stash push -m "描述信息"

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

# 包含被忽略的文件
git stash -a
git stash --all

# 只储藏已跟踪的文件(保留未跟踪文件)
git stash --keep-index

查看 Stash 列表

bash
# 查看所有储藏
git stash list

# 输出示例:
# stash@{0}: On main: 添加新功能
# stash@{1}: On feature: 修复bug
# stash@{2}: WIP on develop: abc123 提交信息

# 查看 Stash 的详细信息
git stash show stash@{0}

# 查看 Stash 的完整差异
git stash show -p stash@{0}

# 查看特定文件的变化
git stash show -p stash@{0} -- path/to/file

应用和删除 Stash

应用 Stash

bash
# 应用最近的 Stash(不删除)
git stash apply

# 应用指定的 Stash
git stash apply stash@{2}

# 应用并从列表中删除
git stash pop

# 应用指定的 Stash 并删除
git stash pop stash@{1}

# 从 Stash 创建新分支
git stash branch <branch-name>
git stash branch <branch-name> stash@{1}

删除 Stash

bash
# 删除最近的 Stash
git stash drop

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

# 删除所有 Stash
git stash clear

应用冲突处理

当应用 Stash 时发生冲突:

bash
# 查看冲突文件
git status

# 手动解决冲突后
git add <resolved-files>
git commit

# 或者放弃应用
git checkout --ours <file>
git checkout --theirs <file>

Stash 工作流程

场景一:紧急修复 Bug

bash
# 1. 当前正在开发新功能,突然需要修复紧急 Bug
git status
# Changes not staged for commit:
#   modified: src/feature.js

# 2. 储藏当前工作
git stash push -m "开发中的新功能"

# 3. 切换到需要修复的分支
git checkout main

# 4. 创建修复分支
git checkout -b hotfix/urgent-bug

# 5. 修复 Bug 并提交
git add .
git commit -m "修复紧急 Bug"

# 6. 合并修复
git checkout main
git merge hotfix/urgent-bug

# 7. 返回原工作分支,恢复工作
git checkout feature
git stash pop

场景二:跨分支应用修改

bash
# 1. 在错误的分支上做了修改
git status
# On branch feature-a
# Changes to be committed:
#   modified: src/utils.js

# 2. 储藏修改
git stash push -m "utils 优化"

# 3. 切换到正确的分支
git checkout feature-b

# 4. 应用储藏
git stash pop

场景三:部分储藏

bash
# 1. 有多个文件修改,只想储藏部分
git status
# modified: src/a.js
# modified: src/b.js
# modified: src/c.js

# 2. 只添加想保留的文件到暂存区
git add src/a.js

# 3. 储藏未暂存的修改
git stash --keep-index

# 现在 src/a.js 的修改还在暂存区
# src/b.js 和 src/c.js 的修改已储藏

场景四:从 Stash 创建分支

bash
# 1. 应用 Stash 时冲突太多,不如创建新分支
git stash branch new-feature stash@{0}

# 这会:
# - 创建新分支
# - 应用 Stash
# - 删除该 Stash

Stash 内部原理

Stash 的存储结构

bash
# Stash 实际上是特殊的提交
# 查看 Stash 的提交信息
git log --oneline --graph stash@{0}

# Stash 包含三个提交:
# 1. 工作目录的状态
# 2. 暂存区的状态(如果有的话)
# 3. 未跟踪文件的状态(如果使用了 -u 或 -a)

Stash 引用

bash
# Stash 存储在 .git/refs/stash
cat .git/refs/stash

# 查看 Stash 日志
git reflog stash

最佳实践

1. 使用描述性信息

bash
# 不推荐
git stash

# 推荐
git stash push -m "WIP: 用户认证功能开发中"

2. 定期清理 Stash

bash
# 查看所有 Stash
git stash list

# 删除不再需要的 Stash
git stash drop stash@{5}

# 或清空所有
git stash clear

3. 不要长期依赖 Stash

bash
# Stash 是临时存储,不适合长期保存工作
# 如果工作需要长期保存,应该创建一个临时分支

# 不推荐:长期保留 Stash
git stash push -m "重要工作"

# 推荐:创建临时分支
git checkout -b temp/work-in-progress
git add .
git commit -m "WIP: 重要工作"

4. 小心使用 -u 和 -a 选项

bash
# -u 会包含未跟踪文件,可能会储藏不该储藏的文件
# -a 会包含被忽略的文件,可能包含敏感信息

# 使用前先检查
git status
git status --ignored

常见问题

Q: 如何查看 Stash 中某个文件的内容?

bash
# 方法一:使用 git show
git show stash@{0}:path/to/file

# 方法二:使用 git stash show
git stash show -p stash@{0} -- path/to/file

Q: 如何只应用 Stash 中的某个文件?

bash
# 使用 git checkout 从 Stash 恢复文件
git checkout stash@{0} -- path/to/file

Q: Stash 会丢失吗?

bash
# 正常情况下不会丢失
# 但 git gc 可能会清理过期的 Stash(默认 90 天)

# 查看即将过期的 Stash
git fsck --unreachable

# 延长 Stash 过期时间
git config stash.reflogExpire 180

Q: 如何在脚本中使用 Stash?

bash
#!/bin/bash

# 安全地使用 Stash
if git diff-index --quiet HEAD --; then
    echo "工作目录干净,无需储藏"
else
    git stash push -m "自动储藏: $(date)"
    STASHED=1
fi

# 执行其他操作...

# 恢复工作
if [ "$STASHED" = "1" ]; then
    git stash pop
fi

总结

Git Stash 是一个实用的工作流程工具:

功能命令说明
创建git stash push -m "msg"储藏当前修改
查看git stash list列出所有储藏
应用git stash apply应用储藏
应用并删除git stash pop应用并删除储藏
删除git stash drop删除储藏
清空git stash clear删除所有储藏

使用建议

  • 为 Stash 添加描述信息
  • 不要长期依赖 Stash 存储工作
  • 定期清理不需要的 Stash
  • 使用 git stash branch 处理复杂冲突