撤销一个git pull操作

25

我见过的关于撤销 git pull 的问题略有不同。

这是我的操作:

在目录 A 中有一个项目(不是仓库)。我在其中初始化了一个仓库,添加了文件,但没有进行任何提交。然后我从仓库 B 拉取,覆盖了一堆我已经暂存的文件。

我本以为可以使用 git reset --hard 来撤消合并。当然,这只是检出了我刚才拉取的提交的 HEAD。

我应该在执行拉取操作前创建一个分支并进行提交,事后诸葛亮。是否有办法让我恢复旧的未暂存文件?


3
未来可能会让你少些烦恼的一件事是 git reset --merge。那些没有受到合并影响的文件保持不变,由于如果您对合并将修改的文件进行了更改,git 将拒绝尝试合并它们,因此它可以很好地覆盖你的基础! - Cascabel
另外,拉取操作是否真的覆盖了暂存文件?这对我来说没有意义。正如我在之前的评论中所说,Git会拒绝合并这种情况。也许是reset --hard命令将它们清除了? - Cascabel
是的,我认为是reset --hard。这有点像rm -rf,在不正确的操作下很危险。 - Benbob
5个回答

31

git pull 命令相当于执行 git fetchgit merge 命令。它是合并步骤覆盖了您的更改。要恢复到合并之前的状态,请使用 git log 查找最新的提交,然后使用 git reset --hard 1234abcd 命令,其中 1234abcd 是所需提交的哈希值。

请注意,在执行重置操作后,git pull 命令将再次合并更改。若要永久撤消更改,请使用 git revert 命令,它会创建一个额外的提交来撤销更改。


1
这通常应该可以工作,但正如问题中所述,他只是暂存了更改。没有提交。因此也没有什么可以重置的。 - geoffreyd
事情是,在合并之前我没有提交任何内容,只有一个暂存区。我很确定我不小心删除了所有文件。 - Benbob
“ORIG_HEAD”是在合并或其他可能危险的命令之前,“HEAD”的状态。不幸的是,正如其他评论者所指出的那样,在这里它没有帮助。 - Mikael S
1
git reset --hard 会覆盖已暂存的更改(git reset 也是如此,但 git reset --soft 不会)。如果更改没有被提交,那么它就没有被保存。 - Jay Conrod
哦,你说得对。我以为merge不能在有未提交更改的存储库上工作。至于数据,我认为暂存的文件被记录在git的内部数据存储中,因此仍然可能从那里挖掘出它们。 - Gintautas Miliauskas

13

3
要么只是重置到上一个HEAD(即存储库中的提交,该提交未从远程更新),要么使用git reflog。后者显示在您的存储库中进行的操作列表,git pull命令应该是其中的一部分。只需将git reset --hard X设置为该命令之前的状态即可。
或者只需在先前的HEAD上创建一个新分支(您可以删除/覆盖以前的分支),在那里进行更改,然后再次执行git pull...

1

我认为你现在无法完全恢复。最好的方法是使用 git status 命令检查哪些文件仍然完好无损。如果未提交的文件不存在于此处,则已丢失。

下次在执行 git pull 前,考虑使用 git stash,或者更好的方法是使用 git fetch


如果你是高级的Git用户,并且这些文件非常重要:

如果这些文件已经被暂存,你可以尝试从对象仓库中提取它们。但这些操作直接涉及到Git的核心部分,我不认为你应该尝试。

如果你真的想要,可以阅读以下内容:


没想到可以藏起来。无论如何,分支似乎更安全一些。总之,我从IDE的历史记录中恢复了所有文件,然后初始化并提交,接着运行了 git-fetch,最后执行了 git-merge。效果非常好。 - Benbob

0

更新于2011年1月17日下午6:53

刚刚重新阅读了您的问题。我忽略了您是从项目b中提取而不是将文件复制到您的项目中。不确定在您的情况下我的答案是否仍然适用。我认为您最好遵循geoffreyd's answer并查看StackOverflow问题Recovering added file after doing git reset --hard HEAD^的答案。

原始答案

只需执行git checkout -- <file>即可。

以下是我运行以确认上述内容的示例...

# Create a test directory and some test files
$ mkdir blah
$ echo "I've been overwritten" > test1.txt
$ cd blah
$ echo "I'm the real test1.txt" > test1.txt
$ git init .
Initialized empty Git repository in /Users/matthew/blah/.git/
$ git add .
$ cp ~/test1.txt .
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   test1.txt
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   test1.txt
#
$ cat test1.txt
I've been overwritten
$ git checkout -- test1.txt
$ cat test1.txt
I'm the real test1.txt

当您执行git status时,它会告诉您使用git checkout -- <file>来放弃工作目录中的更改。如果我正确地理解了你的问题,那就是你想做的事情。


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