简体中文 ▾ 主题 ▾ 最新版本 ▾ git-stash 最后更新于 2.52.0

名称

git-stash - 将脏工作目录中的更改暂存起来

概要

git stash list [<log-options>]
git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
git stash drop [-q | --quiet] [<stash>]
git stash pop [--index] [-q | --quiet] [<stash>]
git stash apply [--index] [-q | --quiet] [<stash>]
git stash branch <branchname> [<stash>]
git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
	     [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]
	     [--pathspec-from-file=<file> [--pathspec-file-nul]]
	     [--] [<pathspec>…​]]
git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
           [-u | --include-untracked] [-a | --all] [<message>]
git stash clear
git stash create [<message>]
git stash store [(-m | --message) <message>] [-q | --quiet] <commit>
git stash export (--print | --to-ref <ref>) [<stash>…​]
git stash import <commit>

描述

当你想要记录工作目录和索引的当前状态,但又想回到干净的工作目录时,请使用 git stash。该命令会将你的本地修改暂存起来,并将工作目录恢复到 HEAD 提交的状态。

可以通过 git stash list 列出此命令暂存的修改,使用 git stash show 查看,并使用 git stash apply 恢复(可能在不同的提交之上)。不带任何参数调用 git stash 等同于 git stash push。默认情况下,暂存项会显示为“WIP on <branchname> …​”,但你可以在创建时提供一个更具描述性的消息。

你创建的最新暂存项存储在 refs/stash 中;更早的暂存项可以在此引用的 reflog 中找到,并使用通常的 reflog 语法命名(例如,stash@{0} 是最新创建的暂存项,stash@{1} 是它之前的那个,stash@{2.hours.ago} 也是可能的)。也可以通过指定暂存索引(例如,整数 <n> 等同于 stash@{<n>})来引用暂存项。

命令

push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-u | --include-untracked] [ -a | --all] [-q | --quiet] [(-m|--message) <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]

将本地修改保存到新的暂存条目中,并将其回滚到 HEAD(在工作树和索引中)。<message> 部分是可选的,用于提供暂存状态的描述。

要快速创建快照,可以省略“push”。在此模式下,不允许使用非选项参数,以防止拼写错误的子命令创建不需要的暂存项。这两个例外是 stash -p(作为 stash push -p 的别名)和路径名(pathspec),它们允许在双连字符 -- 之后出现以消除歧义。

save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-u | --include-untracked] [-a | --all] [-q | --quiet] [<message>]

此选项已被弃用,推荐使用 git stash push。它与“stash push”的区别在于它不能接受路径名。相反,所有非选项参数都被连接起来形成暂存消息。

list [<log-options>]

列出你当前拥有的暂存条目。每个暂存条目都列出了其名称(例如,stash@{0} 是最新的条目,stash@{1} 是它之前的那个,依此类推),创建该条目时所在的当前分支名称,以及该条目基于的提交的简短描述。

stash@{0}: WIP on submit: 6ebd0e2... Update git-stash documentation
stash@{1}: On master: 9cc0589... Add git-stash

该命令接受适用于git log命令的选项来控制显示内容和方式。请参阅 git-log[1]

show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]

显示暂存条目中记录的更改,作为暂存内容与创建暂存条目时提交之间的差异。默认情况下,命令显示 diffstat,但它可以接受git diff已知的任何格式(例如,git stash show -p stash@{1} 以 patch 格式查看第二个最新的条目)。如果未提供<diff-option>,则默认行为由 stash.showStatstash.showPatch 配置变量决定。你还可以使用 stash.showIncludeUntracked 来设置 --include-untracked 是否默认启用。

pop [--index] [-q | --quiet] [<stash>]

从暂存列表中删除一个暂存状态,并将其应用于当前工作树状态之上,即执行 git stash push 的逆操作。工作目录必须与索引匹配。

应用状态可能会因冲突而失败;在这种情况下,它不会从暂存列表中删除。你需要手动解决冲突,然后调用 git stash drop

apply [--index] [-q | --quiet] [<stash>]

pop 类似,但不会从暂存列表中删除状态。与 pop 不同,<stash> 可以是任何看起来像由 stash pushstash create 创建的提交。

branch <branchname> [<stash>]

创建一个名为<branchname>的新分支并检出它,该分支从<stash>最初创建时的提交开始,并将<stash>中记录的更改应用于新的工作树和索引。如果成功,并且<stash>是形式为 stash@{<revision>} 的引用,那么它将删除<stash>

如果你运行 git stash push 的分支发生了足够大的变化,导致 git stash apply 因冲突而失败,这会很有用。由于暂存项应用于 git stash 运行时 HEAD 的提交之上,它会恢复最初的暂存状态而没有冲突。

clear

删除所有暂存条目。请注意,这些条目将可能被垃圾回收,并且可能无法恢复(请参阅下面的示例中的可能策略)。

drop [-q | --quiet] [<stash>]

从暂存条目列表中删除一个单独的暂存条目。

create

创建一个暂存条目(它是一个普通的提交对象),并返回其对象名称,而不将其存储在任何 ref 命名空间中。这旨在对脚本有用。这可能不是你想要的命令;请参阅上面的“push”。

store

将通过 git stash create 创建的给定暂存(一个悬空合并提交)存储到暂存 ref 中,更新暂存 reflog。这旨在对脚本有用。这可能不是你想要的命令;请参阅上面的“push”。

export ( --print | --to-ref <ref> ) [<stash>...]

导出指定的暂存项(或全部,如果未指定),到一个提交链中,该链可以通过正常的 fetch 和 push 机制进行传输,然后通过 import 子命令导入。

import <commit>

从指定的提交(必须由 export 创建)导入指定的暂存项,并将它们添加到暂存列表中。要替换现有的暂存项,请先使用 clear

选项

-a
--all

此选项仅对 pushsave 命令有效。

所有被忽略和未跟踪的文件也会被暂存,然后用 git clean 清理。

-u
--include-untracked
--no-include-untracked

当与 pushsave 命令一起使用时,所有未跟踪的文件也会被暂存,然后用 git clean 清理。

当与 show 命令一起使用时,将暂存条目中的未跟踪文件作为 diff 的一部分显示。

--only-untracked

此选项仅对 show 命令有效。

在 diff 中只显示暂存条目中的未跟踪文件。

--index

此选项仅对 popapply 命令有效。

尝试恢复工作树的更改,以及索引的更改。然而,当出现冲突时,这可能会失败(冲突存储在索引中,因此无法按原样应用更改)。

-k
--keep-index
--no-keep-index

此选项仅对 pushsave 命令有效。

所有已添加到索引的更改都将保持不变。

-p
--patch

此选项仅对 pushsave 命令有效。

交互式地从 HEAD 和工作树之间的 diff 中选择要暂存的块。暂存条目的索引状态将与你的存储库的索引状态相同,其工作树仅包含你交互式选择的更改。然后,这些选定的更改将从你的工作树中回滚。要了解如何操作 --patch 模式,请参阅 git-add[1] 的“交互模式”部分。

选项 --patch 暗示 --keep-index。你可以使用 --no-keep-index 来覆盖此设置。

-U<n>
--unified=<n>

生成具有 <n> 行上下文的 diff。如果配置选项未设置,则默认为 diff.context 或 3。

--inter-hunk-context=<n>

在差异块之间显示上下文,最多达指定行数 <number>,从而合并彼此接近的块。默认为 diff.interHunkContext,如果未设置配置选项则为 0。

-S
--staged

此选项仅对 pushsave 命令有效。

仅暂存当前已暂存的更改。这类似于基本的 git commit,只是状态被提交到暂存区而不是当前分支。

选项 --patch 的优先级高于此选项。

--pathspec-from-file=<file>

此选项仅对 push 命令有效。

路径名(pathspec)将从<file>中读取,而不是从命令行参数中读取。如果<file>正好是 -,则使用标准输入。路径名由 LF 或 CR/LF 分隔。路径名可以按 core.quotePath 配置变量(请参阅 git-config[1])的说明进行引用。另请参阅 --pathspec-file-nul 和全局 --literal-pathspecs

--pathspec-file-nul

此选项仅对 push 命令有效。

仅当与 --pathspec-from-file 一起使用时才有意义。路径名由 NUL 字符分隔,所有其他字符都按字面意思处理(包括换行符和引号)。

-q
--quiet

此选项仅对 applydroppoppushsavestore 命令有效。

安静模式,抑制反馈消息。

--print

此选项仅对 export 命令有效。

创建表示已导出暂存项的提交链,而不将其存储在任何 ref 命名空间中,并将对象 ID 打印到标准输出。这适用于脚本。

--to-ref

此选项仅对 export 命令有效。

创建表示已导出暂存项的提交链,并将其存储到指定的 ref 中。

--

此选项仅对 push 命令有效。

为了消除歧义,将路径名与选项分开。

<pathspec>...

此选项仅对 push 命令有效。

新的暂存条目仅记录与路径名匹配的文件的已修改状态。索引条目和工作树文件也仅对这些文件回滚到 HEAD 的状态,而未匹配路径名的文件则保持不变。

有关更多详细信息,请参阅 gitglossary[7] 中的 pathspec 条目。

<stash>

此选项仅对 applybranchdroppopshowexport 命令有效。

形式为 stash@{<revision>} 的引用。当未给出<stash>时,假定为最新的暂存(即 stash@{0})。

讨论

暂存条目表示为一个提交,其树记录了工作目录的状态,其第一个父提交是创建条目时 HEAD 的提交。第二个父提交的树记录了创建条目时索引的状态,它是 HEAD 提交的子提交。祖先图如下所示:

       .----W
      /    /
-----H----I

其中 HHEAD 提交,I 是记录索引状态的提交,W 是记录工作树状态的提交。

示例

拉取到脏树

当你在进行某项工作时,得知有上游更改可能与你的工作相关。如果你的本地更改与上游更改没有冲突,简单的 git pull 就可以让你继续前进。

然而,在某些情况下,你的本地更改与上游更改发生冲突,git pull 会拒绝覆盖你的更改。在这种情况下,你可以将你的更改暂存起来,执行 pull,然后取消暂存,如下所示:

$ git pull
 ...
file foobar not up to date, cannot merge.
$ git stash
$ git pull
$ git stash pop
中断的工作流

当你在进行某项工作时,你的老板进来要求你立即修复某个问题。传统上,你会将更改提交到一个临时分支以暂存它们,然后返回到原始分支进行紧急修复,如下所示:

# ... hack hack hack ...
$ git switch -c my_wip
$ git commit -a -m "WIP"
$ git switch master
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git switch my_wip
$ git reset --soft HEAD^
# ... continue hacking ...

你可以使用 git stash 来简化上述过程,如下所示:

# ... hack hack hack ...
$ git stash
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git stash pop
# ... continue hacking ...
测试部分提交

当你想要从工作树的更改中创建两个或多个提交,并且想要在提交每个更改之前对其进行测试时,可以使用 git stash push --keep-index

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash push --keep-index    # save all other changes to the stash
$ edit/build/test first part
$ git commit -m 'First part'     # commit fully tested change
$ git stash pop                  # prepare to work on all other changes
# ... repeat above five steps until one commit remains ...
$ edit/build/test remaining parts
$ git commit foo -m 'Remaining parts'
保存无关的更改以供将来使用

当你正在进行大量的更改,并且发现了一个不相关的需要修复的问题,你不想忘记它。你可以进行更改,暂存它们,然后使用 git stash push --staged 将它们暂存起来供将来使用。这类似于提交暂存的更改,只是提交最终进入了暂存区而不是当前分支。

# ... hack hack hack ...
$ git add --patch foo           # add unrelated changes to the index
$ git stash push --staged       # save these changes to the stash
# ... hack hack hack, finish current changes ...
$ git commit -m 'Massive'       # commit fully tested changes
$ git switch fixup-branch       # switch to another branch
$ git stash pop                 # to finish work on the saved changes
恢复错误地清除/删除的暂存条目

如果你错误地删除了或清除了暂存条目,则无法通过正常的安全机制恢复它们。但是,你可以尝试以下命令来获取仓库中仍然存在但不再可达的暂存条目列表:

git fsck --unreachable |
grep commit | cut -d\  -f3 |
xargs git log --merges --no-walk --grep=WIP

配置

本节中以下所有内容均从 git-config[1] 文档中选择性地包含。内容与彼处相同:

stash.index

如果设置为 true,git stash applygit stash pop 的行为将如同 supplied 了 --index。默认为 false。

stash.showIncludeUntracked

如果设置为 true,git stash show 命令将显示暂存条目的未跟踪文件。默认为 false。

stash.showPatch

如果设置为 true,git stash show 命令(不带选项)将以 patch 格式显示暂存条目。默认为 false。

stash.showStat

如果设置为 true,git stash show 命令(不带选项)将显示暂存条目的 diffstat。默认为 true。

GIT

Git[1] 套件的一部分