在开发过程中,我经常将文件的工作版本(但不提交它们(添加到我的 git 存储库中。我继续处理这些文件,直到它们达到可提交阶段,那时我可以提交它们。所以回购如下所示
$ 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 不像以前那样将它们藏起来? 如何一次性存储
- 我的更改,以便在执行存储弹出时,我得到旧状态,而不是新状态?
目前,我手动做
git stash --keep-index
git stash
git stash pop
git add <stashed_files>
git stash pop
问题是
- 它需要 5 个步骤来存储和流行,我正在寻找 2
- 我有时可能不记得有 2 个背靠背的藏匿处,这使任务稍微复杂化。
编辑 - 我更喜欢命令行解决方案,因为我在测试服务器上以类似的方式工作。
我看到这已经回答了,但让我再补充一点,还有一个警告:git stash
有一个小号.
当您在不使用 -p
的情况下运行 git stash
或 git stash save
(默认值为 save
,因此它们是一回事(时,stash
脚本(它位于 git-core
目录中,其位置因 git 安装而异,例如它可能在 /usr/libexec/git-core
或/usr/local/libexec/git-core
中(创建一个包含两个(有时是三个(父提交的提交。 按顺序,这些提交是:
- 当前索引
- 使用
-u
或-a
,未跟踪甚至忽略的文件(它还使用git clean
将它们从工作目录中丢弃(
工作目录 - ,基于当前工作目录和
HEAD
提交之间的增量(这是 Buglet 的来源;见下文(。
然后,它会设置refs/stash
以指向这些提交中的最后一个,即工作目录提交。 此提交作为其父项:
- HEAD 提交,作为
stash^
(第一父级( - 索引提交,作为
stash^2
(第二个父级( - 未跟踪/忽略的提交,作为
stash^3
(第三个父级(,如果存在。
包含存储时的所有内容,但是当您使用git stash pop --index
或git stash apply --index
来恢复"预存储状态"时,小号显示效果最佳。 (我将在下面专门使用git stash apply
,但pop
只是apply
后跟drop
。
现在,如果您只是运行 git stash apply
,正如您所指出的,即使您在运行git stash save
之前已经仔细上演了一些内容,它也会为您提供很多changes not staged for commit
文件。 这是因为无论工作目录状态如何,都可以像这样将这些更改合并在一起要容易得多,包括您是否签出了不同的分支或其他内容,包括在运行git stash apply
之前暂存某些文件。 (事实上,git stash apply
使用 git 的合并代码来引入工作目录更改。
但是,如果您运行 git stash apply --index
,则stash
脚本首先尝试将原始save
时您在其中的内容完全添加到索引中。 (如果尚未暂存任何内容,这将恢复原始状态。 假设它可以做到这一点,然后它会尝试以类似的方式设置工作目录(再次使用合并机制(。 如果它无法正确设置索引,则不会对索引执行任何操作,并建议您重试而不--index
。
这就是小号的用武之地。 假设您从一个文件开始,比如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
在索引中被修改,然后在work-dir中再次修改,但第二次更改将其带回HEAD
提交中的内容。 运行 git stash save
时,存储脚本会意外记录索引版本,就好像它是正在进行的版本一样。
如果您现在执行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
存储脚本的修复是一个单词的更改,但到目前为止似乎没有人喜欢它。 也许问题是,如果您应用没有--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
如果我们查看索引和工作目录版本,我们现在可以看到两个版本的basefile
。
(对存储脚本的一个单词修复是将HEAD
更改为$i_tree
行:
git diff --name-only -z HEAD -- >"$TMP-stagenames" &&
118号线附近。 我将其发布到 git 邮件列表并得到...蟋蟀。:-) )
-index 选项。
git stash
git stash pop --index