如何撤消 git reset --hard HEAD~1?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5473/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I undo git reset --hard HEAD~1?
提问by Paul Wicks
Is it possible to undo the changes caused by the following command? If so, how?
是否可以撤消由以下命令引起的更改?如果是这样,如何?
git reset --hard HEAD~1
回答by Brian Riehman
Pat Notz is correct. You can get the commit back so long as it's been within a few days. git only garbage collects after about a month or so unless you explicitly tell it to remove newer blobs.
Pat Notz 是对的。只要提交是在几天之内,您就可以取回提交。除非您明确告诉它删除较新的 blob,否则 git 仅在大约一个月后进行垃圾收集。
$ git init
Initialized empty Git repository in .git/
$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file1
$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file2
$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1
$ cat file2
cat: file2: No such file or directory
$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2
$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2
$ cat file2
added new file
You can see in the example that the file2 was removed as a result of the hard reset, but was put back in place when I reset via the reflog.
您可以在示例中看到 file2 由于硬重置而被删除,但在我通过 reflog 重置时被放回原位。
回答by Pat Notz
What you want to do is to specify the sha1 of the commit you want to restore to. You can get the sha1 by examining the reflog (git reflog
) and then doing
您要做的是指定要恢复到的提交的 sha1。您可以通过检查 reflog ( git reflog
)来获取 sha1 ,然后执行
git reset --hard <sha1 of desired commit>
git reset --hard <sha1 of desired commit>
But don't wait too long... after a few weeks git will eventually see that commit as unreferenced and delete all the blobs.
但不要等太久……几周后,git 最终会将该提交视为未引用并删除所有 blob。
回答by markmc
The answer is hidden in the detailed response above, you can simply do:
答案隐藏在上面的详细回复中,您可以简单地执行以下操作:
$> git reset --hard HEAD@{1}
(See the output of git reflog show)
(见git reflog show的输出)
回答by sverrejoh
It is possible to recover it if Git hasn't garbage collected yet.
如果 Git 尚未进行垃圾回收,则可以恢复它。
Get an overview of dangling commits with fsck
:
获取悬空提交的概述fsck
:
$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
Recover the dangling commit with rebase:
使用 rebase 恢复悬空提交:
$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
回答by Chris
If you're really lucky, like I was, you can go back into your text editor and hit 'undo'.
如果你真的很幸运,就像我一样,你可以回到你的文本编辑器并点击“撤消”。
I know that's not really a proper answer, but it saved me half a day's work so hopefully it'll do the same for someone else!
我知道这不是一个真正正确的答案,但它为我节省了半天的工作,所以希望它对其他人也能做到!
回答by suhailvs
as far as i know, --hard
will discards uncommitted changes. Since these aren't tracked by git. but you can undo the discarded commit
.
据我所知,--hard
将丢弃未提交的更改。因为这些不是由 git 跟踪的。但您可以撤消discarded commit
.
$ git reflog
will lists:
将列出:
b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....
where 4bac331
is the discarded commit
.
这里4bac331
是discarded commit
。
Now just move the head to that commit::
现在只需将头部移至该提交:
$ git reset --hard 4bac331
回答by Stian H?iland
Example of IRL case:
IRL案例示例:
$ git fsck --lost-found
$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a <- it's this one
$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a
$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a
commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen H?iland <[email protected]>
Date: Wed Aug 15 08:41:30 2012 +0200
*MY COMMIT MESSAGE IS DISPLAYED HERE*
diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*
$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a
$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a
First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.
回答by Ajedi32
In most cases, yes.
在大多数情况下,是的。
Depending on the state your repository was in when you ran the command, the effects of git reset --hard
can range from trivial to undo, to basically impossible.
根据运行命令时存储库所处的状态,其影响git reset --hard
范围可以从微不足道到撤消,再到基本上不可能。
Below I have listed a range of different possible scenarios, and how you might recover from them.
下面我列出了一系列不同的可能情况,以及您可以如何从中恢复。
All my changes were committed, but now the commits are gone!
我所有的更改都已提交,但现在提交不见了!
This situation usually occurs when you run git reset
with an argument, as in git reset --hard HEAD~
. Don't worry, this is easy to recover from!
当您git reset
使用参数运行时,通常会发生这种情况,如git reset --hard HEAD~
. 别担心,这很容易恢复!
If you just ran git reset
and haven't done anything else since, you can get back to where you were with this one-liner:
如果您只是跑步git reset
并且此后没有做任何其他事情,那么您可以使用这个单线回到原来的位置:
git reset --hard @{1}
This resets your current branch whatever state it was in before the last time it was modified (in your case, the most recent modification to the branch would be the hard reset you are trying to undo).
这将重置您当前的分支,无论它在上次修改之前处于什么状态(在您的情况下,对分支的最新修改将是您尝试撤消的硬重置)。
If, however, you havemade other modifications to your branch since the reset, the one-liner above won't work. Instead, you should run git reflog
<branchname>
to see a list of all recent changes made to your branch (including resets). That list will look something like this:
但是,如果你已经自复位做出其他修改您的分支,一内衬上面将无法工作。相反,您应该运行以查看对您的分支所做的所有最近更改(包括重置)的列表。该列表将如下所示:git reflog
<branchname>
7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit
Find the operation in this list that you want to "undo". In the example above, it would be the first line, the one that says "reset: moving to HEAD~". Then copy the representation of the commit before(below) that operation. In our case, that would be master@{1}
(or 3ae5027
, they both represent the same commit), and run git reset --hard <commit>
to reset your current branch back to that commit.
在此列表中找到要“撤消”的操作。在上面的例子中,它是第一行,写着“重置:移动到 HEAD~”的那一行。然后在该操作之前(下方)复制提交的表示。在我们的例子中,这将是master@{1}
(或者3ae5027
,它们都代表相同的提交),然后运行git reset --hard <commit>
以将您的当前分支重置回该提交。
I staged my changes with git add
, but never committed. Now my changes are gone!
我使用 进行了更改git add
,但从未提交过。现在我的改变消失了!
This is a bit trickier to recover from. git doeshave copies of the files you added, but since these copies were never tied to any particular commit you can't restore the changes all at once. Instead, you have to locate the individual files in git's database and restore them manually. You can do this using git fsck
.
这有点难以恢复。git确实有您添加的文件的副本,但是由于这些副本从未与任何特定提交相关联,因此您无法一次恢复所有更改。相反,您必须在 git 的数据库中找到各个文件并手动恢复它们。您可以使用git fsck
.
For details on this, see Undo git reset --hard with uncommitted files in the staging area.
有关这方面的详细信息,请参阅撤消 git reset --hard 在暂存区中使用未提交的文件。
I had changes to files in my working directory that I never staged with git add
, and never committed. Now my changes are gone!
我对我的工作目录中的文件进行了更改,这些更改从未使用git add
,也从未提交过。现在我的改变消失了!
Uh oh. I hate to tell you this, but you're probably out of luck. git doesn't store changes that you don't add or commit to it, and according to the documentation for git reset
:
哦哦。我不想告诉你这个,但你可能不走运。git 不存储您未添加或提交的更改,并且根据以下文档git reset
:
--hard
Resets the index and working tree. Any changes to tracked files in the working tree since
<commit>
are discarded.
- 难的
重置索引和工作树。此后对工作树中跟踪文件的任何更改
<commit>
都将被丢弃。
It's possible that you mightbe able to recover your changes with some sort of disk recovery utility or a professional data recovery service, but at this point that's probably more trouble than it's worth.
您可能可以使用某种磁盘恢复实用程序或专业的数据恢复服务来恢复您的更改,但在这一点上,这可能会带来更多的麻烦。
回答by J?rg W Mittag
If you have not yet garbage collected your repository (e.g. using git repack -d
or git gc
, but note that garbage collection can also happen automatically), then your commit is still there?– it's just no longer reachable through the HEAD.
如果您还没有对您的存储库进行垃圾回收(例如使用git repack -d
或git gc
,但请注意垃圾回收也可以自动发生),那么您的提交仍然存在? - 它只是不再可以通过 HEAD 访问。
You can try to find your commit by looking through the output of git fsck --lost-found
.
您可以尝试通过查看git fsck --lost-found
.
Newer versions of Git have something called the "reflog", which is a log of all changes that are made to the refs (as opposed to changes that are made to the repository contents). So, for example, every time you switch your HEAD (i.e. every time you do a git checkout
to switch branches) that will be logged. And, of course, your git reset
also manipulated the HEAD, so it was also logged. You can access older states of your refs in a similar way that you can access older states of your repository, by using an @
sign instead of a ~
, like git reset HEAD@{1}
.
较新版本的 Git 有一个叫做“reflog”的东西,它是对 refs 所做的所有更改的日志(与对存储库内容所做的更改相反)。因此,例如,每次切换 HEAD 时(即每次执行 agit checkout
切换分支时)都将被记录。而且,当然,您git reset
还操纵了 HEAD,因此它也被记录了下来。您可以以与访问存储库的旧状态类似的方式访问 refs 的旧状态,方法是使用@
符号而不是~
,例如git reset HEAD@{1}
。
It took me a while to understand what the difference is between HEAD@{1} and HEAD~1, so here is a little explanation:
我花了一段时间才明白 HEAD@{1} 和 HEAD~1 的区别是什么,所以这里稍微解释一下:
git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog
So, HEAD~1
means "go to the commit before the commit that HEAD currently points at", while HEAD@{1}
means "go to the commit that HEAD pointed at before it pointed at where it currently points at".
因此,HEAD~1
表示“转到 HEAD 当前指向的提交之前的提交”,而HEAD@{1}
表示“转到HEAD 当前指向的提交之前指向的提交”。
That will easily allow you to find your lost commit and recover it.
这将很容易让您找到丢失的提交并恢复它。
回答by CodeWizard
Before answering lets add some background, explaining what is this HEAD
.
在回答之前让我们添加一些背景,解释一下这是什么HEAD
。
First of all what is HEAD?
First of all what is HEAD?
HEAD
is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD
at any given time. (excluding git worktree
)
HEAD
只是对当前分支上的当前提交(最新)的引用。在任何给定时间
只能有一个HEAD
。(不包括git worktree
)
The content of HEAD
is stored inside .git/HEAD
and it contains the 40 bytes SHA-1 of the current commit.
的内容HEAD
存储在里面.git/HEAD
,它包含当前提交的 40 字节 SHA-1。
detached HEAD
detached HEAD
If you are not on the latest commit - meaning that HEAD
is pointing to a prior commit in history its called detached HEAD
.
如果您不在最新的提交上——这意味着它HEAD
指向历史中的先前提交,它被称为detached HEAD
.
On the command line it will look like this- SHA-1 instead of the branch name since the HEAD
is not pointing to the the tip of the current branch
在命令行上,它看起来像这样 - SHA-1 而不是分支名称,因为HEAD
它没有指向当前分支的尖端
A few options on how to recover from a detached HEAD:
关于如何从分离的 HEAD 中恢复的一些选项:
git checkout
git checkout
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
This will checkout new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point you can create a branch and start to work from this point on.
这将签出指向所需提交的新分支。
此命令将检出给定的提交。
此时您可以创建一个分支并从这一点开始工作。
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# create a new branch forked to the given commit
git checkout -b <branch name>
git reflog
git reflog
You can always use the reflog
as well.git reflog
will display any change which updated the HEAD
and checking out the desired reflog entry will set the HEAD
back to this commit.
您也可以随时使用reflog
。git reflog
将显示更新HEAD
并检出所需引用日志条目的任何更改将设置HEAD
回此提交。
Every time the HEAD is modified there will be a new entry in the reflog
每次修改 HEAD 时都会有一个新条目 reflog
git reflog
git checkout HEAD@{...}
This will get you back to your desired commit
这会让你回到你想要的提交
git reset HEAD --hard <commit_id>
git reset HEAD --hard <commit_id>
"Move" your head back to the desired commit.
“移动”你的头回到所需的提交。
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
- Note: (Since Git 2.7)
you can also use thegit rebase --no-autostash
as well.
- 注意:(从 Git 2.7 开始)
您也可以使用git rebase --no-autostash
。
git revert <sha-1>
git revert <sha-1>
"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be commited while the original commit will remain in the history as well.
“撤消”给定的提交或提交范围。
reset 命令将“撤消”在给定提交中所做的任何更改。
带有撤消补丁的新提交将被提交,而原始提交也将保留在历史记录中。
# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>
This schema illustrate which command does what.
As you can see there reset && checkout
modify the HEAD
.
这个模式说明了哪个命令做什么。
如您所见,reset && checkout
修改HEAD
.