根据运行命令时存储库所处的状态,具有的效果 git reset --hard 可以从琐碎到撤消,到基本上不可能。
git reset --hard
下面我列出了一系列不同的可能方案,以及如何从中恢复。
运行时通常会发生这种情况 git reset 与争论,如在 git reset --hard HEAD~ 。别担心,这很容易恢复!
git reset
git reset --hard HEAD~
如果你刚跑了 git reset 并且没有做任何其他事情,因为你可以回到这个单线的位置:
git reset --hard @{1}
这会将当前分支重置为上次修改之前的状态(在您的情况下,对分支的最新修改将是您尝试撤消的硬重置)。
但是,如果你 有 自复位后对您的分支进行了其他修改,上面的单行无效。相反,你应该跑 git reflog <branchname> 查看最近对您的分支所做的所有更改的列表(包括重置)。该列表看起来像这样:
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
在此列表中找到要“撤消”的操作。在上面的例子中,它将是第一行,即“重置:移动到HEAD~”。然后复制提交的表示 之前 (下面)那个操作。在我们的例子中,那就是 master@{1} (要么 3ae5027 ,它们都代表相同的提交),然后运行 git reset --hard <commit> 将当前分支重置回该提交。
master@{1}
3ae5027
git reset --hard <commit>
git add
恢复起来有点棘手。混帐 不 拥有您添加的文件的副本,但由于这些副本从未与任何特定提交绑定,因此您无法一次性恢复所有更改。相反,您必须在git的数据库中找到各个文件并手动恢复它们。你可以使用 git fsck 。
git fsck
有关详细信息,请参阅 使用暂存区域中的未提交文件撤消git reset --hard 。
哦,哦。我不想告诉你这个,但你可能运气不好。 git不存储您不添加或提交的更改,并根据 文档 git reset :
的 - 硬 强> 重置索引和工作树。 的 自那以后对工作树中跟踪文件的任何更改 <commit> 被丢弃了。 强>
的 - 硬 强>
重置索引和工作树。 的 自那以后对工作树中跟踪文件的任何更改 <commit> 被丢弃了。 强>
<commit>
你有可能 威力 能够使用某种磁盘恢复工具或专业数据恢复服务恢复您的更改,但此时可能比它的价值更麻烦。
在回答之前,我们添加一些背景,解释这是什么 HEAD 。
HEAD
First of all what is HEAD?
HEAD 只是对当前分支上当前提交(最新)的引用。 只能有一个 HEAD 在任何给定的时间。 (除 git worktree )
git worktree
的内容 HEAD 存储在里面 .git/HEAD 它包含当前提交的40字节SHA-1。
.git/HEAD
detached HEAD
如果你没有参加最新的提交 - 意思是这样 HEAD 指向历史上的先前提交它被称为 的 detached HEAD 强> 。
在命令行上,它看起来像这样 - SHA-1而不是分支名称 HEAD 没有指向当前分支的尖端
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
这将检查指向所需提交的新分支。 此命令将签出到给定的提交。 此时,您可以创建一个分支,并从此开始工作。
# 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>
你可以随时使用 reflog 同样。 git reflog 将显示更新的任何更改 HEAD 并检查所需的reflog条目将设置 HEAD 回到这个提交。
reflog
的 每次修改HEAD时,都会有一个新条目 reflog 强>
git reflog git checkout HEAD@{...}
这将使您回到所需的提交
git reset HEAD --hard <commit_id>
“移动”你的头回到所需的提交。
# 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.
git rebase --no-autostash
git revert <sha-1>
“撤消”给定的提交或提交范围。 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>
此模式说明了哪个命令执行的操作。 正如你在那里看到的那样 reset && checkout 修改 HEAD 。
reset && checkout
我刚刚对错误的项目进行了重置。拯救我生命的是Eclipse的当地历史。据说IntelliJ Idea也有一个,所以你的编辑也可以这样做,值得检查一下:
您要做的是指定要还原到的提交的sha1。你可以通过检查reflog获得sha1( git reflog )然后做
git reset --hard <sha1 of desired commit>
但是不要等待太久......几周之后,git最终会将提交视为未引用并删除所有blob。
我所知道的, --hard 将丢弃未提交的更改。因为这些不是由git跟踪的。但你可以撤消 discarded commit 。
--hard
discarded commit
$ git reflog
将列出:
b0d059c HEAD@{0}: reset: moving to HEAD~1 4bac331 HEAD@{1}: commit: added level introduction.... ....
哪里 4bac331 是个 discarded commit 。
4bac331
现在只需将头移至该提交::
$ git reset --hard 4bac331
我知道这是一个老线程...但是由于许多人正在寻找在Git中撤消内容的方法,我仍然认为继续在这里给出提示可能是一个好主意。
当你在git gui中执行“git add”或从左上角到左下角移动任何内容时,文件的内容将存储在blob中,文件内容可以从该blob中恢复。
因此即使文件未提交也可以恢复文件,但必须添加文件。
git init echo hello >> test.txt git add test.txt
现在blob已创建,但它被索引引用,因此在重置之前不会使用git fsck列出。所以我们重置......
git reset --hard git fsck
你会得到一个悬垂的blob ce013625030ba8dba906f756967f9e9ca394464a
git show ce01362
会给你文件内容“你好”回来
为了找到未引用的提交,我在某个地方发现了一个建议。
gitk --all $(git log -g --pretty=format:%h)
我把它作为git gui中的工具,它非常方便。
$ 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
commit f6ce1a403399772d4146d306d5763f3f5715cb5a Author: Stian Gudmundsen H?iland <stian@Stians-Mac-mini.local> 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
First, rewinding head to replay your work on top of it... Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.
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
您可以在示例中看到file2因硬重置而被删除,但是当我通过reflog重置时,它被放回原位。
制作了一个小脚本,使其更容易找到正在寻找的提交:
git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'
是的,它可以用awk或类似的东西制作得相当漂亮,但它很简单,我只是需要它。可能会救别人30秒。
答案隐藏在上面的详细回复中,您可以简单地做到:
$> git reset --hard HEAD@{1}
(见输出 git reflog show )