
暂存了一个文件里的部分修改,接着要切换分支处理别的事。普通的 git stash 会把暂存内容也从工作区拿走;加上 --keep-index 后,暂存版本仍留在当前目录。容易误会的是,这不等于暂存版本没有进 stash。两个临时仓库的对照结果把这两件事分开了。
留在工作区,不代表没被收进 stash
实验从同一份 base 文件开始。先追加 staged 并执行 git add,再追加 unstaged,这样 index 只包含第一处修改,而工作区文件同时含两处。默认执行 stash 后,文件退回 base,index 与工作区都干净;stash 的补丁则包含两行新增内容。
[default]
status:
index diff:
(empty)
worktree diff:
(empty)
file:
base
stash diff:
diff --git a/note.txt b/note.txt
index df967b9..913ae38 100644
--- a/note.txt
+++ b/note.txt
@@ -1 +1,3 @@
base
+staged
+unstaged
加上 --keep-index 后,状态变成 M note.txt。空格位置很重要:首列的 M 表示 index 相对提交有改动,第二列为空,说明工作区没有额外的 unstaged 差异。文件里仍有 base 和 staged 两行。可 stash 里的补丁仍然同时列出 staged 与 unstaged。
[--keep-index]
status: M note.txt
index diff:
diff --git a/note.txt b/note.txt
index df967b9..12caafd 100644
--- a/note.txt
+++ b/note.txt
@@ -1 +1,2 @@
base
+staged
worktree diff:
(empty)
file:
base
staged
stash diff:
diff --git a/note.txt b/note.txt
index df967b9..913ae38 100644
--- a/note.txt
+++ b/note.txt
@@ -1 +1,3 @@
base
+staged
+unstaged
== experiment complete ==
这里的「保留」描述的是执行完成后的当前 index 与工作区,不是在 stash 里只存未暂存部分。忘了这一点,稍后再应用 stash,暂存那行可能会以为是重复修改。需要取回时先检查目标分支是否已经有同一改动。
两种命令留下的状态不同
| 操作 | 执行后 index | 执行后工作区 | stash 内容 |
|---|---|---|---|
git stash push |
干净 | 干净 | staged 与 unstaged 修改 |
git stash push --keep-index |
保留 staged 修改 | 没有额外 unstaged 修改 | staged 与 unstaged 修改 |
表格里 stash 内容看起来相同,这是本次实验最值得记住的地方。选项名容易让人以为 Git 只保存未暂存部分,实际动作是让已经暂存的部分继续留在 index。比较 git stash show -p stash@{0} 才能看到保存边界;只看 git status,会漏掉 stash 里仍有暂存版本这件事。
这个行为适合先提交已暂存部分、把未暂存内容暂时收起的工作流。例如先跑针对暂存内容的检查,确认后提交,再恢复 stash 继续处理剩余修改。这里有个实际取舍:我会把它用于短暂切换,不会把它当作「只 stash unstaged」的快捷写法,因为 stash 里仍带着已暂存版本,恢复时更需要留意重复应用和冲突。
恢复前先看清应用范围
git stash apply 会把 stash 的差异应用到当前目录,但不会自动删除 stash 条目;git stash pop 在应用成功后还会尝试移除该条目。保留 index 的工作流中,当前目录原本已经有 staged 修改,而 stash 本身也含那部分内容。Git 会依据共同基线和补丁尝试合并,不能把「一定产生重复行」当成结论,结果取决于当前内容有没有变化。
在临时仓库里试验的安全边界很简单:先看 git status --short,再用 git stash show -p 查看补丁。若暂存区里已有的修改已经提交到新分支,恢复前尤其要确认 stash 是否包含同一修改。必要时先复制仓库或建临时 worktree,再试 apply。宁可多看一眼补丁,也不在有未提交内容的真实工作区里试一个自己没把握的 pop。
这次脚本使用两个全新的临时仓库,分别运行默认 stash 与 --keep-index,日志保留完整输出。行为在本机 Git 2.50.1(Apple Git-155)实测;其他版本或 stash 配置可能影响显示细节,跨版本没有额外验证。临时目录会在脚本退出时清除,原仓库没有被改动。