在开发过程中,我经常将文件的工作版本(但不提交)添加到我的 git 存储库中。我继续处理这些文件,直到它们达到可提交阶段,当我可以提交它们时。所以 repo 看起来像下面
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: testfile1
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: testfile1
# modified: testfile2
当我做
git stash
,然后做一个 git stash pop
,我得到# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: testfile1
# modified: testfile2
问题
目前,我手动执行
git stash --keep-index
git stash
git stash pop
git add <stashed_files>
git stash pop
问题是
编辑 - 我更喜欢命令行解决方案,因为我在测试服务器上以类似的方式工作。
最佳答案
我看到这已经得到了回答,但让我再补充一点,还有一个警告:git stash
中有一个小号.
当您运行时 git stash
或 git stash save
(默认是 save
所以这些是一样的)不使用 -p
, stash
脚本——它存在于 git-core
目录,其位置因git安装而异,可能在/usr/libexec/git-core
或 /usr/local/libexec/git-core
例如——创建一个带有两个(或有时三个)父提交的提交。这些提交按顺序是:
-u
或 -a
,未跟踪甚至忽略的文件(它还使用 git clean
将它们从工作目录中删除)HEAD
之间的增量提交(这是 buglet 的来源;见下文)。 然后设置
refs/stash
指向这些提交中的最后一个,即工作目录提交。此提交具有作为其父项:stash^
(第一 parent )stash^2
(第二个家长)stash^3
(第三个父级),如果它存在。 这个存储实际上包含了存储时的所有内容,但是当您使用
git stash pop --index
时,buglet 显示效果最好。或 git stash apply --index
恢复“预藏状态”。 (我将在下面单独使用 git stash apply
,但 pop
只是 apply
后跟 drop
。)现在,如果你只是运行
git stash apply
,正如您所指出的,它为您提供了很多 changes not staged for commit
即使您在运行之前仔细地准备了一些文件 git stash save
.这是因为像这样将这些更改 merge 在一起要容易得多,无论工作目录状态如何,包括您是否已 checkout 不同的分支或其他任何内容,也包括您是否在运行 git stash apply
之前暂存了一些文件。 . (实际上,git stash apply
使用 git 的 merge 代码来引入工作目录的更改。)如果您运行
git stash apply --index
但是,stash
脚本首先尝试将您在原始 save
时所拥有的内容添加到索引中。 . (如果还没有暂存,这将恢复您的原始状态。)假设它可以做到这一点,它然后尝试类似地设置工作目录(再次使用 merge 机制)。如果它不能正确设置索引,它对索引没有任何作用,并建议您在没有 --index
的情况下重试。 .这就是 buglet 出现的地方。假设你从一个文件开始,比如
basefile
,没有变化。您进行更改并进行此操作:$ cat basefile
base
$ git status --short
$ echo add to basefile >> basefile; git add basefile
但随后您决定希望工作目录副本与
HEAD
没有任何变化修订:$ ed basefile
21
2d
w
5
q
$ git status --short
MM basefile
这里的棘手之处在于
basefile
在索引中修改,然后在工作目录中再次修改,但第二次更改将其带回 HEAD
中的内容犯罪。当您运行时 git stash save
, stash 脚本不小心记录了索引版本,就好像它是正在进行的版本一样。如果你现在做
git stash apply --index
并运行 git status --short
:$ git stash save
Saved working directory and index state WIP on master: 94824e1 initial
HEAD is now at 94824e1 initial
stash created
$ git stash apply --index
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: basefile
#
$ git status --short
M basefile
这里 git 已经将索引版本恢复到索引中,然后将工作目录版本设置为与索引版本中相同的内容:
$ cat basefile
base
add to basefile
stash 脚本的修复是一个单词的更改,但到目前为止似乎没有人喜欢它。也许问题在于,如果您在没有
--index
的情况下应用存储,这有效地将索引更改(额外的行, add to basefile
)与任何内容结合在一起,以便工作目录版本具有额外的行。但是,这与索引和工作目录版本不同时的行为方式不一致:$ git stash drop
Dropped refs/stash@{0} (61c83c866bc522c58df62320b77e647ffd28aa95)
$ echo base > basefile
$ git status --short
$ echo add to basefile >> basefile
$ git add basefile
$ ed basefile
21
2c
different change
w
22
q
$ git status --short
MM basefile
$ git stash save
Saved working directory and index state WIP on master: 94824e1 initial
HEAD is now at 94824e1 initial
$ git stash apply
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: basefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$ cat basefile
base
different change
在这里,通过“混合”索引和工作树的变化,但不应用
--index
,我们只恢复工作树的变化。(幸运的是,由于我们使用
apply
而不是 pop
,我们现在可以改变主意:$ git reset --hard HEAD
HEAD is now at 94824e1 initial
$ git stash apply -q --index
$ git status --short
MM basefile
如果我们查看 index 和 work-dir 版本,我们现在可以看到
basefile
的两个版本.)(对 stash 脚本的一个词修复是在以下行中将
HEAD
更改为 $i_tree
:git diff --name-only -z HEAD -- >"$TMP-stagenames" &&
大约在第 118 行。我将其发布到 git 邮件列表并得到了......蟋蟀。 :-) )
关于Git stash 删除添加的更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19287386/