你如何告诉git仅存储索引?

99

我刚刚使用了git add -p将一堆更改添加到索引中,然后我意识到我错过了一个应该放在上一个提交中的更改。

现在我不能使用commit --amend,因为我已经将所有这些新更改添加到了索引中,而且我不想使用'git reset'将它们全部从索引中删除,因为重新添加它们需要很长时间。

我需要的是像git stash这样的东西,只会隐藏索引-它应该让工作文件保持原样。然后我可以隐藏索引,添加缺少的更改,提交它,然后弹出隐藏并使我的索引恢复到原来的状态。

看起来git stash似乎无法做到这一点,但我是否遗漏了什么?谢谢!


2
我认为你只需要使用git commit命令 - 它会将你的索引(index)创建成一个提交(commit)。在这之后,Kevin Ballard的回答解释了如何合理地重写历史记录... - Mark Longair
14
听起来你想要类似于“git stash --keep-index”的东西,但是针对工作目录,也就是“--working-tree”。我也是这样想的,但是这个功能并不存在。 - Leif Gruenwoldt
从版本2.35开始,git在git stash push子命令中提供了--staged选项。 (为了方便引用@user3840170的答案。) - tom
16个回答

38

2
在合并冲突的中间,这对我不起作用。我得到了一堆“需要合并”的文件,然后出现以下错误:致命错误:git-write-tree:构建树时出错 无法保存当前索引状态 - theazureshadow
2
谢谢,这太棒了!我以为Stash只能保存所有文件,这对我的工作流程来说是一个很大的改进。 - nickel715

32

为什么不能作弊?

git stash --keep-index

让所有目前未在索引中的内容都被清除掉。

然后,

git stash

只获取已经暂存的内容来创建一个藏匿库。

git stash pop

首先将更改加入存储区,然后...

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

清理工作树,然后

git stash pop --index

要恢复您的索引更改。


4
如果你做了很多更改,这会让人感到相当害怕。你只需要保存并恢复索引,就像我在这里的答案中所做的那样 - user11658273
1
如果你不小心搞砸了,你仍然可以从reflog中提取原始更改。话虽如此,对于那些不太熟悉git的人,我建议采用更简单的方法。我看到你的方法唯一的问题是(如果我没记错的话)git apply是用来将差异应用到它所取自的提交上的。在你的情况下,你是在额外的更改之后应用它,所以如果hunk行偏移量发生变化,它可能无法干净地应用。 - doliver

31

自版本2.35起, git在git stash push子命令中提供了--staged选项:

-S
--staged

此选项仅适用于pushsave命令。

仅存储当前已暂存的更改。这类似于基本的git commit,只是状态被提交到stash而不是当前分支。

--patch选项优先于此选项。


我在git 2.36上尝试了这个功能。git stash push --staged对于一个文件的部分提交处理不了,但其他方面正常工作。 - Kai Oezer
3
而索引的同义词列表不断增长:现在我们有一些命令需要将 --cached 视为索引,有些命令只是称其为 --index(包括 git stash,它具有 --keep-index 选项)以及 --staged - Kaz
这与 OP 需要的相反,不是吗?感觉应该在问题下发表评论。 - Tomáš Hübelbauer
2
@TomášHübelbauer 不是的,这个命令会把暂存区中的文件储藏起来。相反的命令是 git stash --keep-index - Melebius

30

最简单的方法是先不修改此更改,创建新的提交,然后创建第二个提交,包含你想要使用的修改,并使用 git rebase -i 将其与原始 HEAD 合并。

另一种方法是创建提交,标记它,使用 git reset HEAD^ 回滚,添加该更改并修改 HEAD ,然后挑选你标记的提交。


1
如果你使用的是相对较新的git版本,还可以查看“autosquash”和git commit --fixup选项。 - Tyler
需要注意的是,你必须指定你想要rebase的commit:在这种情况下,使用git rebase -i HEAD~2 - Auron
是的,获胜答案。我只想补充一点,如果您希望将所有内容作为单独的提交,您可能需要重新排序提交并将其压缩到适当的提交中。 - BenKoshy

11
提交你的索引,创建一个修补提交,并使用自动压缩重新进行变基:
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
3
不过我觉得这个更容易理解。 - Agent Friday

11

git stash 实际上会创建一个提交记录,其中包含索引的内容,然后在其之上添加所有已跟踪文件的内容。

查看它:创建一个存储区,然后运行

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

技术上讲,当你使用stash命令时,可以通过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

8

Emacsmagit 命令可以使用 magit-stash-index 将修改暂存。


7

这里的大多数回答都相当复杂,危险或者在所有情况下都不起作用。由于有很多“在飞行中”的更改(包括索引和工作树中的更改),我甚至不想考虑硬重置、隐藏、过早提交每个更改,只是为了将其带回生活中,或其他任何可能有效的操作。唯一想要做的事情就是改变索引本身。

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

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

好的,这就是全部内容了!将当前索引保存为差异(diff),重置它,添加和提交您的单独更改,然后重新应用所保存的索引中的更改。

如果您想要分离的更改已经应用到索引中(并且您不想麻烦地删除它们),那么在git apply之前,您必须使用一个额外的git reset HEAD^来重置索引到您执行此操作时的状态。否则,补丁文件将无法再次应用(因为它已经随您的提交而应用),git 绝对不会部分应用补丁文件。


2
如果索引和工作树中的现有更改足够分离,以至于重置不会妨碍您在第3行中识别要提交的更改,则可以很好地工作。 - bers
如果使用自定义的 diff 驱动程序,例如二进制文件,这是否有效? - shadowtalker
@shadowtalker 理论上来说,它应该是这样的;我想补丁和差异的概念都是一样的,不管驱动程序的具体实现细节如何。 - Kamafeather

6
这似乎有效。我尚未在所有情况下进行测试,以确保它具有健壮性:
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]

2
如果索引中添加了新文件,这段代码会出现错误并产生奇怪的结果。 - Robin Green

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

5
欢迎来到 Stack Overflow!虽然这段代码可以解决问题,但是添加一些解释会有助于提高你的帖子质量并使内容更加易懂。请注意,你的回答是为未来的读者而写的,而这些人可能不知道你提供代码建议的原因。请尽量避免在你的代码中添加过多的解释性注释,因为这会降低代码和解释的可读性! - Blue
2
git stash -k 会将索引的更改也存入暂存区,因此在这些步骤之后,索引和非索引的更改都被修改了。 - Alexey Biryukov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接