Git 存储会删除添加的更改



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

问题

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

目前,我手动做

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

问题是

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

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

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

当您在不使用 -p 的情况下运行 git stashgit 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 --indexgit 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

最新更新