7

在开发过程中,我经常将文件的工作版本(但不提交)添加到我的 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

当我做 a git stash,然后做 a 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

问题

  1. 为什么 git 不像以前那样存储它们?
  2. 如何一次性存储我的更改,以便在执行存储弹出时,我得到旧状态,而不是新状态?

目前,我手动做

git stash --keep-index
git stash
git stash pop
git add <stashed_files>
git stash pop

这个问题是

  1. 存储和弹出需要 5 个步骤,我正在寻找 2 个
  2. 我有时可能不记得有 2 个背靠背的藏匿处,这会使任务稍微复杂化。

编辑 - 我更喜欢命令行解决方案,因为我在测试服务器上以类似的方式工作。

4

2 回答 2

5

我看到这已经回答了,但让我再补充一点,还有一个警告:在git stash.

当你在不使用的情况下运行git stashgit stash save(默认是save相同的东西)时-pstash脚本——它位于git-core目录中,其位置因 git 安装而异,它可能在/usr/libexec/git-core/usr/local/libexec/git-core例如——创建一个包含两个 (或者有时是三个)父提交。按顺序,这些提交是:

  • 当前索引
  • 带有-uor -a,未跟踪甚至被忽略的文件(它还用于git clean将它们从工作目录中删除)
  • 工作目录,基于当前工作目录和HEAD提交之间的增量(这是 buglet 的来源;见下文)。

然后它设置refs/stash为指向这些提交中的最后一个,即工作目录提交。这个提交作为它的父母:

  • HEAD 提交,作为stash^(第一父)
  • 索引提交,作为stash^2(第二个父级)
  • 未跟踪/忽略的提交,作为stash^3(第三父),如果它存在。

git stash pop --index这个存储实际上包含存储时的所有内容,但是当您使用或git stash apply --index恢复“预存储状态”时,buglet 显示得最好。(我将在git stash apply下面专门使用,但pop后面apply紧跟drop.)

现在,如果您只是运行git stash apply,正如您所指出的,它会为您提供大量changes not staged for commit文件,即使您在运行之前已经仔细准备了一些内容git stash save。这是因为像这样将这些更改合并在一起要容易得多,无论工作目录状态如何,包括您是否签出不同的分支或其他任何内容,以及是否在运行git stash apply. (实际上,git stash apply使用 git 的合并代码来引入工作目录更改。)

但是,如果您运行git stash apply --index,该stash脚本首先会尝试将您在原始save. (如果还没有上演任何内容,这将恢复您的原始状态。)假设它可以做到这一点,然后它会尝试类似地设置工作目录(再次使用合并机制)。如果它无法正确设置索引,它不会对索引做任何事情,并建议您在没有--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 脚本的修复是一个单词的更改,但到目前为止似乎没有人喜欢它。也许问题在于,如果您在不使用 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 邮件列表并得到了……蟋蟀。:-) )

于 2013-10-10T21:16:31.813 回答
3

使用 --index 选项。

git stash
git stash pop --index
于 2013-10-10T05:20:29.000 回答