如何撤销已暂存带有更改的文件,并保留其暂存时的更改?

10

假设我编辑了一个文件

echo "hi" > someVersionedFile.txt

//Then I staged the file
git add .
git status

<console reads>
 Changes to be committed
 new file: someVersionedFile.txt 

现在我对文件进行了额外的更改

echo "hi again file" >> someVersionedFile.txt

//Then I restage the file with these changes
git add .
git status

<console reads>
 Changed but not commited
 modified file: someVersionedFile.txt

问题:我如何恢复上一次暂存的版本?由于没有提交,这是否可能?


我非常确定这是不可能的,但我也想知道它是否可行! - Drew Noakes
不确定你是如何做到的,但如果你现在提交,只有暂存的更改才会被提交。然后,你可以将该文件还原到刚刚所做的提交。 - andypaxo
@andypaxo这并不是问题所在。更确切地说,问题是:如果你将一个文件a暂存,并对其进行了修改;然后再次进行修改,那么如何将该文件还原到被暂存时的状态——考虑到该文件已经有/仍有其他修改? - stackoverflow
2
@thatDudeThatDoesThatThing 这就是提交的全部意义。你正在进行版本承诺。你告诉版本控制它应该跟踪文件的当前状态。如果这有助于你 - 把git想象成一个图形,当你提交时,你向该图形插入一个节点,你只能在节点(版本)之间移动。 - Benjamin Gruenbaum
3个回答

6
您可能可以做到这一点,但是没有单一简单的命令可以为您完成此操作。
当您执行git add时,文件已被添加到存储库中,但目前除索引外没有任何指向它的东西。当您进行第二个git add时,新文件(版本)将被添加到存储库中,并且索引和第一个文件版本之间的链接将被替换为新链接。但是第一个对象仍然存在。
您可以使用git fsck --dangling获取存储库中当前未被任何内容引用的blob对象列表,但然后您需要使用git showgit cat-file等逐个查看它们,以确定哪个是您想要的文件。找到正确的文件后,您可以使用git show HASH > somefile.txt(也许还有git add somefile.txt)。
当然,如果自第二次git add以来您已经执行了任何git prunegit gc等操作,则可能已经从存储库中删除了原始文件。
以下是一个快速示例:
$ git init foo
Initialized empty Git repository in foo/.git/
$ cd foo
$ echo blah > foo.txt
$ git add foo.txt
$ echo blarg > foo.txt
$ git add foo.txt
$ git fsck --dangling
Checking object directories: 100% (256/256), done.
dangling blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
$ git show 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
blah
$

4
您无法这样做。Git只能将文件恢复到先前的提交版本,而不能回退到之前的暂存版本。这是因为在提交之前,文件不会被输入到git的仓库中。(您可以在Coding Horror中了解有关最佳提交实践的更多信息)
也许您可以适度使用“撤消”按钮?(如果您已经在编辑器中编辑了代码,那么显然通过“echo”写入文件是无法撤消的)。

1

你的意思是想要回退到暂存版本?没错,你可以这么做。最简单的方法可能是提交你的暂存更改,从该提交中检出文件,然后重置你的分支:

git commit -m "Temporary commit"
git checkout HEAD -- /path/to/file_you_want_to_revert
git reset HEAD~

抱歉,我没有注意到您已经使用新更改重新设置了文件的部分。很抱歉,但其他答案是正确的:这是不可能的(或者至少不是很容易的)。我会保留这个答案,以防有人遇到类似的问题,但尚未覆盖缓存。

2
虽然这不是正确的答案,但你可以通过 git checkout /path/to/file_you_want_to_revert 命令来实现相同的效果,而无需指定分支名称。 - mihi
谢谢你的提示 - 只是用不同的方式表达,git checkout [path] 将会还原目标文件到它的暂存版本,但前提是该文件存在于暂存区!如果你在一个没有暂存的文件上运行相同的命令,它将被还原到提交时的状态。所以如果你没有意图回滚到某个暂存区,你可能会丢失工作 :) - jocull

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