git stash——不仅仅是恐慌保存(部分暂存、命名暂存以及其他内容)
超出恐慌保存:命名暂存区、暂存区列表、显示 -p、使用 --patch 的部分暂存区、apply 与 pop 的区别,以及你最终会遇到的未跟踪文件问题。
你学会了 git stash 在慌乱中。有人在功能开发中途通知你,你需要立即切换分支,而暂存(stash)是最快退出的方式。拯救了这一天。
然后你有三个暂存,忘了里面的内容,错误地将其中一个应用到错误的分支上,于是你认为暂存功能出了问题。其实它并没有问题。你只需要掌握更多命令即可。
未跟踪的文件让你困扰(请先阅读此部分)
git stash 仅保存 已跟踪的 文件——Git 已知的文件。你尚未提交的新文件对 Git 是不可见的。
# You created a new file mid-feature
echo "temp work" > new-feature.js
git stash
# new-feature.js is still sitting there — stash ignored it entirely
添加 -u 以包含未跟踪文件:
git stash push -u
此外还有 -a (--all) 也包含被忽略的文件。这几乎从来不是你想要的结果——它会暂存你的 node_modules 更改和 .env 文件,并使恢复变得极其困难。
在后悔之前为暂存命名
默认的暂存消息是:
stash@{0}: WIP on main: a3f1c2d Update dependencies
当你有来自三个不同半完成功能的三个暂存时,这毫无意义。使用 git stash push -m 来命名它们:
git stash push -u -m "wip: oauth token refresh flow"
git stash push -u -m "experiment: lazy load images on scroll"
git stash push -u -m "fix: header z-index issue"
现在 git stash list 实际上是可以读取的:
stash@{0}: On main: fix: header z-index issue
stash@{1}: On feature/images: experiment: lazy load images on scroll
stash@{2}: On feature/auth: wip: oauth token refresh flow
通过索引应用特定的暂存:
git stash apply stash@{2} # brings back the auth work
在应用前检查:stash show -p
git stash show 会显示更改的文件概要。添加 -p 以获取完整的差异:
git stash show -p stash@{2}
这是大多数人跳过然后后悔的命令。没有它,你将盲目地将更改恢复到一个自你暂存以来可能已大幅变动的分支上。一个快速的 show -p 只需十秒钟,就能告诉你即将应用的内容。
如果你想将暂存差异与文件当前状态并排比较,将两者粘贴到 文本比较 工具中——比在脑海中整理要快得多。 git diff stash@{N}..HEAD -- path/to/file 应用与弹出:一个真正重要的区别
这两个命令都会恢复你的暂存。一个关键区别:
= 应用并删除暂存条目
git stash pop= 应用,保留暂存条目git stash apply如果你
并遇到合并冲突,Git 会在你解决任何问题之前就丢弃暂存条目。此时你有一个有冲突的工作树,且没有暂存引用可以回退。 pop 在解决冲突期间保留条目,然后手动清理:
apply 额外的
# Safer workflow when conflicts are possible
git stash apply stash@{0}
# resolve any conflicts
git stash drop stash@{0} # explicit cleanup once you're happy
步骤在暂存代表数小时工作时是值得的。 drop 部分暂存使用 –patch
有时你只想暂存部分更改。你在一个文件中既有 bug 修复,又有半个新功能,你希望提交修复,同时暂存功能代码。
) 打开一个逐块交互会话:
git stash push --patch (或者 -p对于每个块,你获得与
git stash push -p -m "wip: new feature half"
相同的 y/n/s/q 界面。如果 git 的自动分割不够精细,输入 git add -p将一个块分割成更小的部分。虽然比普通暂存慢,但它是不创建临时分支情况下干净地分割脏工作树的最佳方式。 s 一个需要注意的地方:
模式不包含未跟踪文件,因此无法与 --patch 结合使用。如果你有属于你暂存功能的新未跟踪文件,你需要先 -u它们,使其变为跟踪文件,然后再运行部分暂存。 git add 真实使用场景
在功能开发中途进行上下文切换。
当评审者在你深入编写未完成代码时,对另一个 PR 留下紧急反馈。使用命名暂存,切换分支,完成评审,回来后弹出。没有 WIP 提交,没有分支操作。 验证一次干净的测试运行。
git stash push -u -m "wip: refactor auth middleware"
git checkout fix/urgent-prod-bug
# ... review and fix ...
git checkout feature/auth-refactor
git stash pop
你想确认你的测试在干净的工作树上通过——而不是你的半完成更改意外泄漏到测试环境: 这会捕获到测试仅因本地修改而通过的情况。在拥有共享测试固定文件的仓库中,这种情况比你想象的更常见。
git stash push -u
npm test # or pytest, cargo test, whatever
git stash pop
在有冲突的脏工作树下切换分支。
Git 拒绝检查出分支,因为你的工作树中的更改会被覆盖。先暂存,切换分支,再恢复。比 仅仅为了切换分支要快得多。 git commit --fixup git 暂存速查表
暂存已跟踪的更改(简写:
| 命令 | 作用 |
|---|---|
git stash push | 包含未跟踪文件 git stash) |
git stash push -u | 使用描述性名称暂存 |
git stash push -m "name" | 未跟踪 + 命名(你最常使用的组合) |
git stash push -u -m "name" | 交互式部分暂存(逐块) |
git stash push -p | 列出所有暂存 |
git stash list | 暂存中文件变更的概要 |
git stash show stash@{N} | 暂存的完整差异 |
git stash show -p stash@{N} | 应用暂存并保留条目 |
git stash apply stash@{N} | 应用最近的暂存并删除条目 |
git stash pop | 删除特定的暂存条目 |
git stash drop stash@{N} | 删除所有暂存条目 |
git stash clear | 从暂存中创建一个新分支并应用它 |
git stash branch <branchname> | 暂存分支的逃生通道 |
还有一个值得掌握的命令:
。它在你暂存的提交点创建一个新分支,应用暂存,并在应用干净时删除它。当你暂存的更改已经大到值得拥有自己的分支时,这是正确的做法——而且它完全避免了冲突问题,因为你是在它原本的树上重新播放暂存。 git stash branch <branchname>修复 90% 暂存痛苦的习惯:使用
命名一切,并在你确信更改已干净集成前使用 -m。额外的 apply 而不是 pop 步骤花费两秒钟。丢失一个你需要的暂存代价要高得多。 drop git stash — 超越恐慌拯救(部分暂存、命名暂存及其他)2
