在 Git 的日常使用中,git stash 常被视为一个简单的“临时保存”工具:手头工作没做完,突然要切分支修 bug,于是 git stash 一下,回来再 git stash pop。这个用法没错,但只发挥了它三成的能力。当遇到部分文件暂存、多次暂存管理、冲突恢复、甚至从暂存中精准提取某段代码时,git stash 的高级技巧能显著提升效率。本文将从暂存、部分暂存与冲突恢复三个维度,系统梳理 git stash 的进阶用法。
一、基础回顾:stash 到底存了什么
git stash 默认会保存两样东西:工作区中已跟踪文件的修改,以及暂存区中的内容。但它不会保存未跟踪文件(untracked files)和被忽略文件(ignored files)。这是很多人在恢复时发现“文件不见了”的根源。
一个完整的 stash 提交实际上是一个特殊的合并提交,包含工作树状态和索引状态。理解这一点,才能理解后续的 --index、--staged 等选项。
常用基础命令:
git stash # 暂存已跟踪文件的修改
git stash -u # 同时暂存未跟踪文件
git stash -a # 同时暂存未跟踪和忽略文件
git stash list # 查看暂存列表
git stash pop # 恢复并删除最近一次暂存
git stash apply # 恢复但保留暂存记录
git stash drop # 删除最近一次暂存
二、部分暂存:只保存你想保存的
实际开发中,我们经常同时改了好几个文件,但只想暂存其中一部分,以便先提交另一部分。git stash 提供了 -p 和 --staged 两种精准控制方式。
1. 交互式部分暂存:git stash -p
-p(--patch)会逐个代码块(hunk)询问你是否要暂存。这非常适合“一个文件里既有调试代码又有正式修改”的场景。
git stash push -p
执行后,Git 会展示每个 hunk,并给出选项:
y:暂存这个 hunkn:不暂存s:将当前 hunk 拆分成更小的 hunke:手动编辑 hunkq:退出
例如,你在 app.js 中既加了 console.log 调试,又修复了一个逻辑错误。通过 -p 可以只暂存调试代码,把逻辑修复留在工作区继续提交。
2. 只暂存已 add 的内容:git stash --staged
如果你已经用 git add 把要暂存的部分放进了暂存区,可以直接:
git stash push --staged
这只会保存暂存区中的修改,工作区中未 add 的改动保持不变。这个用法在“暂存一部分、提交另一部分”的工作流中极其高效。
3. 指定文件或路径暂存
git stash push -m "修复登录逻辑" src/login.js src/auth.js
配合 -m 添加描述,避免 stash list 里全是 WIP on main 这样的默认信息。路径可以是文件、目录或通配符。
三、多次暂存的管理与精准恢复
当你有多个 stash 时,git stash list 会显示类似:
stash@{0}: On main: 修复登录逻辑
stash@{1}: On main: 调试支付流程
stash@{2}: WIP on main: 3a4b5c6 初始提交
恢复指定 stash:
git stash apply stash@{1}
git stash pop stash@{1}
apply 与 pop 的区别在于:pop 恢复后会删除该 stash,apply 则保留。在不确定是否要保留时,优先用 apply。
查看 stash 内容而不恢复
git stash show stash@{1} # 查看文件变更统计
git stash show -p stash@{1} # 查看完整 diff
从 stash 中提取单个文件
有时你只想从某个 stash 中拿回一个文件,而不是全部恢复:
git checkout stash@{1} -- src/config.js
这会把 src/config.js 从 stash 中检出到工作区,stash 本身不受影响。这是处理“暂存里混入了不该提交的文件”时的利器。
四、冲突恢复:当 stash pop 失败时
git stash pop 最令人头疼的情况是冲突。冲突发生时,Git 会尝试合并,但不会自动删除 stash。此时工作区会留下冲突标记,stash 仍然保留在列表中。
冲突发生后的处理步骤
- 查看冲突文件:
git status会显示both modified的文件。 - 手动解决冲突:编辑文件,保留需要的内容,删除
<<<<<<<、=======、>>>>>>>标记。 - 标记为已解决:
git add <file>。 - 不要执行
git commit:stash 恢复不是一次提交,只需git add后继续工作即可。 - 手动删除 stash:确认无误后执行
git stash drop stash@{0}。
如果冲突太复杂,想放弃恢复:
git checkout -- . # 放弃工作区修改(谨慎)
git stash apply # 重新尝试,或换用其他方式
用 git stash branch 优雅解决冲突
当 stash 与当前分支差异过大时,更安全的方式是基于 stash 创建新分支:
git stash branch fix-login stash@{0}
这个命令会:
- 以 stash 创建时的提交为基础创建新分支
fix-login; - 检出该分支;
- 应用 stash 内容;
- 如果成功,自动删除该 stash。
这样冲突会在一个干净的分支上处理,不会污染当前工作区。这是处理复杂 stash 冲突的推荐做法。
五、实用技巧与注意事项
- 给 stash 命名:始终使用
-m,例如git stash push -m "feat: 用户头像上传"。 - stash 不是备份:stash 存在本地
.git/refs/stash中,不会推送到远程。重要修改应及时提交到分支。 - 避免长期堆积:stash 列表过长容易遗忘,建议每周清理一次,用
git stash list检查。 pop与apply的选择:不确定时用apply,确认后再drop。- 恢复时保留索引状态:
git stash pop --index会尝试恢复暂存区状态,适合需要保持 add 状态的场景。
结语
git stash 远不止“临时保存”一个功能。通过 -p 实现部分暂存,通过 --staged 精准控制暂存区,通过 stash@{n} 管理多次暂存,再配合 stash branch 处理冲突,你可以把工作区切换、代码审查、紧急修复等场景处理得游刃有余。下次再遇到“改到一半要切分支”的情况,不妨试试这些高级用法,让 Git 真正成为你工作流中的得力助手。
未经允许不得转载:任鹏个人博客 » Git stash 高级用法:暂存、部分暂存与冲突恢复


朋友圈点赞图在线生成源码