您如何告诉git仅隐藏索引?


73

我刚刚使用“ git add -p”向索引添加了一堆更改,并且我刚刚意识到我错过了应该在上一次提交中进行的更改。

我现在不能提交-修改,因为我已将所有这些新更改添加到索引中,并且我不想使用'git reset'将所有这些更改从索引中删除,因为添加它们会花费很多时间再回来。

我需要的是类似“ git stash”的东西,它只会存储索引-它应该不理会工作文件。然后,我可以存储索引,添加缺少的更改,提交它,然后弹出存储并将索引恢复到原来的状态。

看起来'git stash'不能做到这一点,但是我缺少什么吗?谢谢!


2
我认为这只是git commit您想要的-它需要您的索引并从中创建一个提交。凯文·巴拉德(Kevin Ballard)的答案解释了在这样做之后如何合理地重写历史……
马克·朗伊尔

9
听起来好像您想要类似的东西,git stash --keep-index但对于工作树。即--working-tree。我也是,它不存在。
Leif Gruenwoldt,2012年

Answers:


26

最简单的方法是立即放弃所做的更改,进行新的提交,然后仅使用要用于修改的更改创建第二个提交,然后使用git rebase -i原始HEAD压缩该更改。

一种替代方法是进行提交,对其进行标记,使用回滚git reset HEAD^,添加一个更改并修改HEAD,然后选择已标记的提交。


1
git commit --fixup如果您使用的是相对较新版本的git,也请查看“自动南瓜”和选项。
MatrixFrog 2011年

应该注意的是,git rebase -i HEAD~2在这种情况下,您必须指出要从哪个提交重新确定基准。
奥龙

36

我发现的最接近的东西是git stash --patch。它引导您完成对工作树和索引的所有更改,让您选择存储的内容。

http://www.kernel.org/pub/software/scm/git/docs/git-stash.html


1
在合并冲突中,这对我不起作用。我得到了一堆“需求合并”文件,然后:致命:git-write-tree:构建树时出错无法保存当前索引状态
theazureshadow 2012年

1
谢谢,这真棒,我认为存储只能保存所有文件,这对我的工作流程有很大的改进
Nick715 2013年

25

为什么不作弊?

git stash --keep-index

以获取当前不在索引中的所有内容。然后,

git stash

可以隐瞒上演的内容。

git stash pop

第一个存储区,添加您的更改。然后,

git commit --amend ...
git reset --hard

清理工作树,然后

git stash pop --index

找回索引更改。


1
如果您进行很多更改,这将非常令人恐惧。您只需要保存和恢复索引,就像我在此处的回答中所做的那样

如果碰巧将其弄乱了,您仍然可以将原始更改从reflog中拉出来。就是说,对于那些不太熟悉git的人,我建议使用一种更简单的方法。我所看到的唯一问题是(IIRC)git apply的意思是将diff应用于它来自的提交。在您的情况下,您需要在进行其他更改后应用它,因此,如果粗线偏移量发生了更改,则可能无法完全应用。
20:07的

10

提交您的索引,创建一个fixture提交,并使用自动压榨进行变基:

git commit
git add -p                         # add the change forgotten from HEAD^
git commit --fixup HEAD^           # commits with "fixup! <commit message of HEAD^>"
git rebase --autosquash -i HEAD~3

感谢您的建议,但是如果您仔细观察,这就是已经接受的答案所建议的内容:-)
Malvineous

1
但是我发现这更容易理解。
特工

10

git stash 确实确实创建了具有索引内容的提交,然后在其顶部添加了所有跟踪文件的内容的提交

要查看此内容:创建一个存储,然后运行

git log --oneline --graph stash@{0}

因此从技术上讲,当您隐藏时,可以通过stash@{0}^2以下方式获取索引:

$ git show --name-only stash@{0}^2
$ git checkout stash@{0}^2 -- .

您还可以隐藏,然后获取跟踪但未添加的文件的内容:

# get the diff between what was indexed and the full stashed content :
$ git diff -p stash@{0}^2 stash@{0}  >  diff.patch
# apply this diff :
$ git apply diff.patch

3
您也可以git stash apply --index使用git checkout .
816-8055


5

这似乎有效。我没有在所有情况下都对其进行测试以确保其健壮性:

git commit -m _stash && git stash && git reset HEAD^ && git stash save  && git stash pop stash@{1}

但是,它可以有效地临时提交索引,存储工作目录,还原提交以恢复索引,将其另存为另一个存储,然后从存储中再次还原原始工作目录。

通过将其添加为git别名可以简化此操作:

[alias]
    istash = "!f() { git commit -m _stash && git stash && git reset HEAD^ && git stash save $1 && git stash pop stash@{1}; }; f"

这使我可以像这样使用它:

git istash [optional stash name]

3
git stash -k
git stash
git stash apply stash@{1}
git stash drop stash@{1}

3
欢迎使用Stack Overflow!尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。也请尽量不要在代码中添加解释性注释,因为这会降低代码和解释的可读性!
再见StackExchange

2
git stash -k也会将索引更改纳入存储。因此,在执行这些步骤之后,将同时修改索引更改和非索引更改。
Alexey Biryukov

3

这里的大多数答案都非常复杂,危险,或者在所有情况下都不起作用。在进行中时有很多更改(在索引和工作树中),我什至不想考虑硬重置,存储,过早地提交每个更改,只是为了使其恢复生命或其他那应该工作。我唯一想做的就是更改索引本身。

幸运的是,有一种简单的方法可以做到这一点!

git diff --cached > 1.diff
git reset
# add and commit changes that should be separate
git apply --cached 1.diff

在那里,您拥有了!将当前索引另存为差异,将其重置,添加并提交单独的更改,然后将更改重新应用到保存的索引。

如果您要分离的更改已应用到索引(并且您不想麻烦删除它们),则必须先使用一个附加选项git reset HEAD^才能git apply将索引重置为使用时的状态差异 否则,该修补程序将不会再次应用(因为您的提交已经应用了git该修补程序),并且绝对会拒绝部分应用该修补程序。


2

这是我过去想出的一个小脚本,可以做到这一点:

(注意:我最初将此内容发布在https://stackoverflow.com/a/17137669/531021上,但它似乎也适用于此。这些问题并非完全相同,因此我认为这可能是两个答案情况)

#!/bin/sh

# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`

# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`

# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`

# get back to a clean state with no changes, staged or otherwise
git reset -q --hard

# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to suceed
git cherry-pick -n $INDEXCOMMIT
git stash

# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT

CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
    # If there are no conflicts, it's safe to reset, so that
    # any previously unstaged changes remain unstaged
    #
    # However, if there are conflicts, then we don't want to reset the files
    # and lose the merge/conflict info.
    git reset -q
fi

您可以将上面的脚本保存在git-stash-index路径中的某个位置,然后可以将其作为git stash-index调用

# <hack hack hack>
git add <files that you want to stash>
git stash-index

现在,存储区包含一个新条目,该条目仅包含您已暂存的更改,而工作树仍包含任何未暂存的更改。

主要问题是,您可能无法干净地删除索引更改而不引起冲突,例如,如果工作树包含依赖于索引更改的更改。

在这种情况下,任何此类冲突都将保留在通常的未合并冲突状态中,类似于在执行摘樱桃/合并之后。

例如

git init
echo blah >> "blah"
git add -A
git commit -m "blah"

echo "another blah" >> blah
git add -A
echo "yet another blah" >> blah

# now HEAD contains "blah", the index contains "blah\nanother blah"
# and the working tree contains "blah\nanother blah\nyetanother blah"

git stash-index

# A new stash is created containing "blah\nanother blah", and we are
# left with a merge conflict, which can be resolved to produce
# "blah\nyet another blah"

我在Windows上并成功地与Windows快捷方式结合来运行bash脚本。我个人向​​该echo "INDEXTREE: $INDEXTREE"脚本添加了类似的命令,因此,如果出现问题,我将能够看到哪里(但您需要一种稍后使窗口保持打开状态的方法)。
Qwertie

2

我必须这样做,最后使用了一些用于脚本编写的git stash选项。Git stash create让我们创建(但不应用)stash对象(包括索引)。Git stash存储将其添加到git stash堆栈中,而无需执行git reset-难于git stash save隐式执行。实际上,这是通过将存储对象添加到堆栈中并手动重置索引来存储索引:

# This will add an entry to your git stash stack, but *not* modify anything
git stash store -m "Stashed index" $(git stash create)

# This will reset the index, without touching the workspace.
git reset --mixed 

现在,您已经有效地保存了索引,完成后可以执行git stash pop --index。

一个警告是,即使您只关心索引,创建的存储对象也包含工作空间中更改的文件和索引,因此即使您尝试使用堆栈从堆栈弹出,也有可能发生冲突--index标志(表示“还从存储中应用索引”,而不是“仅从存储中应用索引”)。在这种情况下,您可以在弹出之前执行“ git reset --hard”(因为您要重置的更改也恰好与之后立即弹出或应用的更改相同,所以它不像它似乎。)


0

如果添加准备提交给索引的文件,但只想暂存它们,则可以使用下面的功能。

>> momomo.com.git.stash.added

要么

>> momomo.com.git.stash.added "name of the  stash"

重击功能:

momomo.com.git.stash.added() {
    local name="$1";

    if [[ "${name}" == "" ]]; then
        name="$(date)"
    fi

    # This will stash everything, but let the added ones remain
    # stash@{1} 
    git stash --keep-index

    # This will stash only the remaining ones
    # @stash@{0}
    git stash save "${name}"

    # Restore everything by applying the first push stash which is now at index 1
    git stash apply stash@{1}

    # Then drop it
    git stash drop stash@{1}

    # At the top of the stash should now be only the originally indexed files
}

请注意,您现在需要将内容重新添加到索引中。


0

这是一种(至少)简单的食谱(至少要遵循):

git commit -m "Will come back and this will be removed, no worries"
git stash save "will drop it, no worries"
git reset --soft HEAD~1 # getting rid of previous revision
git stash save "this is what I really wanted to stash, set the right message"
git stash pop stash@{1} # get files that I didn't want to stash on the working tree
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.