Git存储删除添加的更改

时间:2013-10-10 04:56:51

标签: git git-stash git-index

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

问题

  1. 为什么git不像以前那样藏匿他们?
  2. 如何一次性存储我的更改,以便在进行隐藏弹出时,我会获得较旧的状态,而不是较新的状态?
  3. 目前,我手动执行

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

    问题是

    1. 藏匿和保护需要5个步骤流行,我正在寻找2
    2. 我有时可能不记得有两个背靠背的东西,这使任务稍微复杂化。
    3. 编辑 - 我更喜欢命令行解决方案,因为我在测试服务器上以类似的方式工作。

2 个答案:

答案 0 :(得分:5)

我看到这已经得到了解答,但是让我再补充一点,并发出警告:git stash中有一个小错误。

当您运行git stashgit 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指向最后一个提交,即工作目录提交。这个提交有其父母:

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

此存储实际上包含存储时所有内容,但当您使用git stash pop --indexgit stash apply --index恢复“预存状态”时,该错误最佳显示。 (我将在下方使用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 --indexstash脚本首先尝试将索引添加到原始{{1 }}。 (如果还没有暂存,则会恢复原始状态。)假设它可以执行此操作,然后尝试类似地设置工作目录(再次使用合并机制)。如果它无法正确设置索引,则它对索引不执行任何操作,并建议您在没有save的情况下重试。

这是buglet的用武之地。假设您从一个文件开始,比如--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 在索引中被修改,然后在work-dir中再次修改,但第二次更改将其恢复为basefile提交中的内容。当您运行HEAD时,存储脚本会意外地记录索引版本,就像它是正在进行中的版本一样。

如果您现在执行git stash save并运行git stash apply --index

git status --short

这里git已将索引版本恢复到索引中,然后将工作目录版本设置为与索引版本相同的内容

$ 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

存储脚本的修复是一个单词更改,但到目前为止似乎没有人喜欢它。也许问题在于,如果您应用隐藏而不使用 $ 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

如果我们查看index和work-dir版本,我们现在可以看到$ git reset --hard HEAD HEAD is now at 94824e1 initial $ git stash apply -q --index $ git status --short MM basefile 的两个版本。)

(对隐藏脚本的单字修复是将行中的basefile更改为HEAD

$i_tree

第118行。我把它发布到git邮件列表并得到了...蟋蟀。 :-))

答案 1 :(得分:3)

使用--index选项。

git stash
git stash pop --index