← 返回博客

Git stash详解:save、apply、pop和drop

tutorial git

什么是 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。