Git Stash 完全指南:临时保存工作区的艺术

前言

在 Git 日常开发中,我们经常遇到这样的场景:正在开发一个功能,修改了一堆文件,突然需要切换到其他分支修复紧急 bug,但当前修改又不想提交。这时候 git stash 就派上用场了。本文将深入讲解 Git Stash 的原理、用法和最佳实践。

一、什么是 Git Stash?

1.1 核心概念

git stash 是 Git 提供的一个**栈(Stack)**数据结构,用于临时保存工作区和暂存区的修改,让工作目录恢复到干净状态(HEAD 状态)。

1.2 三个工作区域回顾

text

复制代码
工作区 (Working Directory)    ← 你实际修改文件的地方
    ↓ git add
暂存区 (Staging Area/Index)   ← 准备提交的文件
    ↓ git commit
版本库 (Repository/HEAD)      ← 已提交的历史版本

1.3 Stash 的本质

Stash 本质上是一个后进先出(LIFO)的栈结构

text

复制代码
    入栈 push ↓                  ↑ 出栈 pop
    ┌─────────┐
    │ stash③ │ ← stash@{0} (最新)
    ├─────────┤
    │ stash② │ ← stash@{1}
    ├─────────┤
    │ stash① │ ← stash@{2} (最旧)
    └─────────┘

二、基础命令详解

2.1 git stash - 保存当前修改

bash

复制代码
# 最基础的用法:保存所有已跟踪文件的修改
git stash

# 等价于
git stash push

执行效果

  • ✅ 保存暂存区(staged)的修改

  • ✅ 保存工作区(unstaged)的修改

  • ❌ 不保存未跟踪的新文件

  • ❌ 不保存被 .gitignore 忽略的文件

  • 工作目录恢复到 HEAD 状态(干净状态)

示例

bash

复制代码
# 初始状态
$ echo "new feature" >> app.js
$ git add app.js
$ echo "bug fix" >> utils.js

$ git status
Changes to be committed:
  modified: app.js        # 暂存区

Changes not staged:
  modified: utils.js      # 工作区

# 执行 stash
$ git stash
Saved working directory and index state WIP on main: abc1234 last commit

$ git status
nothing to commit, working tree clean  # 完全干净!

2.2 git stash pop - 恢复并删除

bash

复制代码
# 恢复栈顶的 stash 并删除该记录
git stash pop

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

特点

  • 恢复 stash 中的修改到工作区

  • 自动删除已恢复的 stash 记录

  • 如果冲突,修改会保留但 stash 不删除

与 apply 的区别

bash

复制代码
# pop = apply + drop
git stash pop    # 恢复 + 删除
git stash apply  # 只恢复,不删除
git stash drop   # 只删除,不恢复

2.3 git stash apply - 恢复但不删除

bash

复制代码
# 恢复栈顶的 stash,stash 记录保留
git stash apply

# 恢复指定的 stash
git stash apply stash@{1}

使用场景

  • 想把同一个 stash 应用到多个分支

  • 不确定恢复后是否会有问题,先试试看

2.4 git stash drop - 删除 stash

bash

复制代码
# 删除栈顶的 stash
git stash drop

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

# 清空所有 stash
git stash clear

三、进阶命令详解

3.1 保存未跟踪的文件

bash

复制代码
# -u 或 --include-untracked:包括未跟踪的新文件
git stash -u

# 示例
$ touch newfile.txt        # 新建文件,未 git add
$ git stash -u             # 会保存 newfile.txt

3.2 保存所有文件(包括被忽略的)

bash

复制代码
# -a 或 --all:保存所有文件,包括 .gitignore 中忽略的
git stash -a

3.3 添加描述信息

bash

复制代码
# 带描述的 stash,方便后续查找
git stash push -m "修复登录页面样式"

# 或者
git stash save "修复登录页面样式"  # 旧语法

# 查看时更清晰
$ git stash list
stash@{0}: On main: 修复登录页面样式
stash@{1}: WIP on main: abc1234 某个提交

3.4 只保存部分文件

bash

复制代码
# 交互式选择要 stash 的代码块
git stash -p

# 只 stash 特定文件
git stash push app.js utils.js

# 只 stash 特定文件(带描述)
git stash push -m "只保存前端文件" app.js utils.js

3.5 保持暂存区不变

bash

复制代码
# --keep-index:stash 工作区的修改,但保留暂存区
git stash --keep-index

# 使用场景:想测试暂存区的代码,临时去掉工作区的干扰

3.6 从 stash 创建分支

bash

复制代码
# 将 stash 恢复到一个新分支
git stash branch <branch-name>

# 等价于:
git checkout -b <branch-name>
git stash pop

使用场景:stash 的代码与当前分支冲突严重,需要在独立分支解决。

四、查看与检查

4.1 查看 stash 列表

bash

复制代码
# 列出所有 stash
git stash list

# 输出示例
stash@{0}: WIP on main: abc1234 fix: 修复登录bug
stash@{1}: On develop: def5678 feat: 新功能开发中

4.2 查看 stash 内容

bash

复制代码
# 查看 stash 的简要信息
git stash show

# 查看 stash 的详细 diff
git stash show -p

# 查看指定 stash
git stash show stash@{1}
git stash show -p stash@{1}

4.3 查看 stash 中的文件名

bash

复制代码
# 只显示文件名
git stash show --name-only

五、完整使用场景

场景1:开发中临时切换分支

bash

复制代码
# 1. 正在开发功能,修改了很多文件
$ git status -s
 M app.js
 M utils.js
 M style.css

# 2. 需要紧急修复 bug
$ git stash push -m "新功能开发-登录模块"

# 3. 切换到 bug 修复分支
$ git checkout hotfix

# 4. 修复 bug 并提交
$ git add .
$ git commit -m "fix: 紧急修复支付bug"

# 5. 切回开发分支
$ git checkout feature

# 6. 恢复之前的工作
$ git stash pop

场景2:多个 stash 的管理

bash

复制代码
# 保存第一个任务
$ git stash push -m "任务1:登录页面"

# 保存第二个任务
$ git stash push -m "任务2:数据列表"

# 保存第三个任务
$ git stash push -m "任务3:图表优化"

# 查看所有 stash
$ git stash list
stash@{0}: On feature: 任务3:图表优化
stash@{1}: On feature: 任务2:数据列表
stash@{2}: On feature: 任务1:登录页面

# 先恢复任务2(不是最新的任务3)
$ git stash pop stash@{1}

场景3:部分文件暂存

bash

复制代码
# 修改了3个文件,只想 stash 其中2个
$ git stash push app.js utils.js -m "暂存app和utils"

$ git status
Changes not staged:
  modified: style.css  # 这个文件还在工作区

场景4:stash 冲突处理

bash

复制代码
# 恢复 stash 时发生冲突
$ git stash pop
Auto-merging app.js
CONFLICT (content): Merge conflict in app.js
# stash 没有被删除

# 解决冲突
$ vim app.js  # 手动解决冲突标记

# 标记为已解决
$ git add app.js

# 手动删除 stash
$ git stash drop

# 或者放弃恢复
$ git reset --hard HEAD
$ git stash pop

场景5:将 stash 应用到不同分支

bash

复制代码
# 在 feature 分支 stash
$ git stash

# 切换到 develop 分支
$ git checkout develop

# 应用 feature 分支的 stash
$ git stash apply  # 用 apply 而不是 pop,保留 stash

# 如果还要应用到其他分支
$ git checkout release
$ git stash apply

六、最佳实践与技巧

6.1 命名规范

bash

复制代码
# ✅ 好的实践:有意义的描述
git stash push -m "[WIP] 登录模块 - 表单验证未完成"
git stash push -m "[BUG] 修复支付流程中的空指针 - 等待后端接口"

# ❌ 不好的实践:没有描述
git stash

6.2 定期清理

bash

复制代码
# 查看 stash 列表
git stash list

# 删除不用的 stash
git stash drop stash@{2}
git stash drop stash@{3}

# 或者一次性清空
git stash clear

# 💡 建议:stash 数量不要超过5个,太多了容易混乱

6.3 使用别名提高效率

bash

复制代码
# 在 ~/.gitconfig 中添加
[alias]
    ss = stash
    sl = stash list
    sp = stash pop
    sa = stash apply
    sd = stash drop
    sc = stash clear
    sw = stash show

# 使用
git ss -m "快速暂存"
git sl
git sp

6.4 stash 与 WIP 提交的选择

bash

复制代码
# 什么时候用 stash?
✅ 临时切换分支(几分钟到几小时)
✅ 代码还没到可以提交的程度
✅ 需要快速保存现场

# 什么时候用 WIP 提交?
✅ 需要保存较长时间的修改
✅ 需要推送到远程备份
✅ 需要与他人共享进度

# WIP 提交示例
git add .
git commit -m "WIP: 新功能开发中"
# 回来后继续开发,最后用 rebase 合并
git reset HEAD~1  # 撤销 WIP 提交,保留修改

6.5 查看 stash 的完整差异

bash

复制代码
# 查看 stash 相对于原始位置的完整 diff
git stash show -p stash@{0}

# 对比 stash 与当前工作区的差异
git diff stash@{0}

# 查看 stash 中某个文件的差异
git diff stash@{0} -- app.js

七、常见问题与解决

Q1: pop 时发生冲突怎么办?

bash

复制代码
# pop 冲突后,stash 不会被删除
# 1. 手动解决冲突文件
# 2. git add <解决的文件>
# 3. git stash drop  # 手动删除 stash

Q2: 不小心删除了 stash 能恢复吗?

bash

复制代码
# 1. 找到被删除的 stash 的 commit hash
git fsck --unreachable | grep commit | cut -d ' ' -f3 | xargs git log --merges --no-walk --grep=WIP

# 2. 恢复指定的 stash
git stash apply <commit-hash>

Q3: stash 的文件在哪里?

bash

复制代码
# stash 存储在 .git/refs/stash
cat .git/refs/stash

# 使用 git log 查看 stash 历史
git log --oneline --graph stash

Q4: 如何只 stash 暂存区或只 stash 工作区?

bash

复制代码
# 只 stash 工作区(保留暂存区)
git stash --keep-index

# 只 stash 暂存区(保留工作区)
git stash --staged  # Git 2.35+

# 旧版本需要两步:
git stash --keep-index  # 先 stash 工作区
git stash               # 再 stash 暂存区
git stash pop stash@{1} # 恢复工作区的修改

八、命令速查表

命令 功能 常用场景
git stash 保存当前修改 临时切换任务
git stash -u 包括未跟踪文件 有新建文件
git stash -m "描述" 带描述的暂存 多个 stash 需要区分
git stash pop 恢复并删除 恢复最新暂存
git stash apply 恢复不删除 应用到多个分支
git stash list 查看列表 检查所有暂存
git stash show 查看内容 确认暂存内容
git stash drop 删除指定 清理不用的暂存
git stash clear 清空所有 大清理
git stash branch <name> 创建分支并恢复 解决严重冲突
git stash -p 交互式暂存 部分代码暂存

九、总结

git stash 是 Git 工作流中的"暂停键",掌握它能让你更灵活地管理开发过程:

  1. 理解栈结构:后进先出,pop 总是取最新的

  2. 命名很重要 :带 -m 参数的描述能避免混乱

  3. 善用 apply:不确定时用 apply 而不是 pop

  4. 定期清理:避免 stash 列表堆积过多

  5. WIP 提交是替代方案:需要长期保存或远程备份时使用

记住核心原则:stash 是临时性的,提交是永久性的。根据实际需求选择合适的工具,让版本控制更高效。


希望这篇指南能帮助你更好地理解和使用 Git Stash。如果在实践中有任何问题,欢迎交流讨论!

相关推荐
feibaoqq1 小时前
Atlas边端板卡AI识别:部署方法、技术实现、优劣及应用场景
人工智能·低空经济·低空安防
小保CPP1 小时前
OpenCV C++将多张图像合并为webp动图
c++·人工智能·opencv·计算机视觉
老梁agent1 小时前
告别硬编码 System Prompt:Prompt 六层编译引擎设计与实现
agent
Xzaveir1 小时前
企业号码展示不可观测怎么办:状态机、拨测事件与异常回放
android·人工智能
FII工业富联科技服务1 小时前
从灯塔工厂到AI Factory新模式:AI正在重构制造业的四大核心能力
大数据·运维·人工智能·重构·ar·制造
前端开发江鸟1 小时前
从一个最小 Runtime Demo 看懂:陌生的 599 为什么不能重试
人工智能
AI小白Lin1 小时前
33 个 AI 专家全票通过?那问题才刚开始
人工智能·架构
Spey_Events1 小时前
【核心议题发布】聚焦深度维修与 AI 智慧革新!2026中国民用航空维修智造展——议题重磅发布!
大数据·人工智能
中杯可乐多加冰1 小时前
我把整个机器人足球仓库交给 Doubao-Seed-Evolving,它帮我优化了一套足球战术
人工智能