什么是 Git Stash?
你正在开发一个功能,突然有紧急的事情需要处理。需要在主 branch 上修复一个 bug,或者有同事需要你审查他们的 pull request。你还没准备好 commit 正在进行的工作,但你无法在工作目录中有未 commit 的更改时切换 branch。这正是 git stash 被设计来解决的问题。
Git stash 会取出你未 commit 的更改——包括已 staging 和未 staging 的——并将它们保存到一个临时存储区域。你的工作目录会恢复到干净的状态,与最后一次 commit 一致。当你准备好时,可以把这些更改恢复回来。可以把它想象成把工作放到架子上去处理其他事情,然后回来从你离开的地方继续。
基本用法:Stash、Apply 和 Pop
将更改保存到 stash
最简单的形式是:
git stash
这会获取所有已跟踪的修改文件和 staging 中的文件并存储它们。你的工作目录变得干净。请注意,未跟踪的文件(从未添加到 Git 的文件)默认不会被 stash。要包含它们,使用:
git stash -u
或者要包含所有内容,甚至包括被忽略的文件:
git stash -a
用 apply 恢复更改
当你完成了临时任务,想要恢复 stash 中的工作时,使用:
git stash apply
这会将 stash 中的更改恢复到你的工作目录,但保留 stash 条目不变。stash 仍然在架子上,如果你想将相同的更改应用到多个 branch,这会很有用。
用 pop 恢复更改
git stash pop
Pop 的工作方式与 apply 相同,但在应用后还会删除 stash 条目。当你只是想恢复工作而不需要保留 stash 时,这是更常见的选择。
关键区别:apply 保留 stash,pop 在恢复后删除它。当你可能再次需要 stash 时使用 apply。当你不再需要时使用 pop。
为 Stash 添加消息
默认情况下,Git 会用自动生成的描述来标记 stash,如 WIP on main: a3b4c5d commit message。当你有多个 stash 时,这并不太有用。你可以添加描述性消息:
git stash push -m "refactoring the auth module"
这使得在以后列出 stash 时更容易识别每个 stash 的内容。
管理多个 Stash
列出你的 stash
Git 维护一个 stash 栈。你可以用以下命令查看所有 stash:
git stash list
输出看起来像这样:
stash@{0}: On main: refactoring the auth module
stash@{1}: WIP on feature/checkout: 9f2e1d0 add cart logic
stash@{2}: WIP on main: 7c8d9e1 update dependencies
最新的 stash 始终是 stash@{0}。每个新 stash 会将旧的推到栈的下方。
Apply 或 pop 特定的 stash
默认情况下,apply 和 pop 操作最新的 stash。要定位特定的 stash,通过索引引用它:
git stash apply stash@{2}
git stash pop stash@{1}
查看 stash 的内容
在应用 stash 之前,你可能想查看里面有什么:
git stash show stash@{0}
这会显示已更改文件的摘要。要查看完整的 diff,添加 -p:
git stash show -p stash@{0}
Stash 特定文件
有时你不想把所有东西都 stash。也许你只想暂存一两个文件的更改。从 Git 2.13 开始,你可以这样做:
git stash push -m "sidebar layout changes" src/components/Sidebar.tsx src/styles/sidebar.css
只有指定的文件会被 stash。其他所有内容保留在你的工作目录中。
删除和清除 Stash
删除单个 stash
如果你不再需要某个特定的 stash,用以下命令删除它:
git stash drop stash@{1}
这会删除该 stash 条目。剩余的 stash 会自动重新编号。
清除所有 stash
要一次性删除所有 stash:
git stash clear
请谨慎使用此命令。无法撤销。所有 stash 中的更改都会被永久删除。
从 Stash 创建 Branch
有时你 stash 了一些更改,然后意识到它们值得有自己的 branch。无需先应用 stash 再创建 branch,Git 提供了一个快捷方式:
git stash branch new-feature-branch stash@{0}
这会从 stash 最初创建时的 commit 开始创建一个新 branch,应用 stash 并删除它。当在当前 branch 上应用 stash 会导致冲突时,这特别有用。
常见陷阱
- 忘记 stash。stash 很容易被遗忘。定期运行
git stash list来检查是否有应该被应用或删除的遗留 stash。 - Stash 冲突。如果自你 stash 以来代码发生了重大变化,应用 stash 可能会产生 merge 冲突。用处理任何 merge 冲突的相同方式来解决它们。
- 依赖 stash 而不是 commit。如果你发现自己经常使用 stash,考虑改为 commit 你的进行中的工作。你随时可以在以后 amend 或 squash 这些 commit。stash 最适合快速、短期的上下文切换,而不是长期存储。
在 GitSquid 中使用 Stash
GitSquid 在 commit 图上直接显示 stash,让你一眼就能看到存在哪些 stash 以及它们是从哪个 commit 创建的。右键点击 stash 会打开一个上下文菜单,提供 apply、pop、drop 或清除所有 stash 的选项。这使得管理 stash 比输入命令更快,特别是当你有多个 stash 需要检查或清理时。
快速参考
| 命令 | 作用 |
|---|---|
git stash |
Stash 已跟踪的更改 |
git stash -u |
包含未跟踪文件一起 stash |
git stash push -m "msg" |
带描述消息的 stash |
git stash list |
列出所有 stash |
git stash apply |
恢复 stash,保留条目 |
git stash pop |
恢复 stash,删除条目 |
git stash drop stash@{n} |
删除特定 stash |
git stash clear |
删除所有 stash |
git stash show -p |
查看 stash 的完整 diff |
git stash branch <name> |
从 stash 创建 branch |
Git stash 是那种看似微不足道但在需要时非常重要的工具之一。一旦你熟练掌握它,在任务之间切换上下文就会变得无缝。用消息保持 stash 的有序,定期清理旧的 stash,当不需要保留 stash 时使用 pop 而不是 apply。