如何从当前状态恢复为在某个提交时创建的快照?
如果我做 git log
,那么我得到以下输出:
$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <me@me.com>
Date: Thu Nov 4 18:59:41 2010 -0400
blah blah blah...
commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <me@me.com>
Date: Thu Nov 4 05:13:39 2010 -0400
more blah blah blah...
commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <me@me.com>
Date: Thu Nov 4 00:55:06 2010 -0400
And yet more blah blah...
commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <me@me.com>
Date: Wed Nov 3 23:56:08 2010 -0400
Yep, more blah blah.
如何从11月3日恢复到提交,即提交 0d1d7fc
?
30 回答
在回答之前,让我们添加一些背景,解释这个
HEAD
是什么 .首先是什么是HEAD?
HEAD
只是对当前分支上当前提交(最新)的引用 . 在任何给定时间只能有一个HEAD
(不包括git worktree
) .HEAD
的内容存储在.git/HEAD
中,它包含当前提交的40字节SHA-1 .分离了HEAD
如果你不在最新的提交 - 意味着
HEAD
指向历史上的先前提交它被称为 detached HEAD .在命令行上它看起来像这样 - SHA-1而不是分支名称,因为
HEAD
没有指向当前分支的尖端:关于如何从分离的HEAD中恢复的几个选项:
git checkout
这将检查指向所需提交的新分支 . 此命令将签出到给定的提交 .
此时,您可以创建一个分支,并从此开始工作:
git reflog
您也可以随时使用
reflog
.git reflog
将显示更新HEAD
的任何更改,并且检出所需的reflog条目会将HEAD
设置回此提交 .Every time the HEAD is modified there will be a new entry in the reflog
这将使您回到所需的提交
git reset HEAD --hard <commit_id>
“移动”你的头回到所需的提交 .
git rebase --no-autostash
.此架构说明了哪个命令执行的操作 . 如你所见
reset && checkout
修改HEAD
.在GitKraken你可以这样做:
右键单击要重置的提交,选择:重置为此提交/硬盘:
再次右键单击提交,选择:当前分支名称/推送:
点击强制推送:
Obs. :您需要小心,因为硬重置后的所有提交历史都会丢失,并且此操作是不可逆转的 . 你需要确定你在做什么 .
这很大程度上取决于“恢复”的含义 .
暂时切换到其他提交
如果你想暂时回到它,傻瓜,然后回到你所在的位置,你所要做的就是检查所需的提交:
或者,如果你想在那里做出提交,那么在你做的时候继续做一个新的分支:
要回到原来的位置,只需查看您再次访问的分支 . (如果你做了更改,就像转换分支时一样,你必须在适当的时候处理它们 . 你可以重置它们把它们丢弃;你可以藏匿,结账,存放pop以带走它们;你可以提交如果你想要那里的分支,他们到那里的一个分支 . )
硬删除未发布的提交
另一方面,如果你想真正摆脱自那时以来所做的一切,那么有两种可能性 . 一,如果您还没有发布任何这些提交,只需重置:
如果你陷入困境,你已经抛弃了你的本地变化,但你至少可以通过重新设置来回到原来的位置 .
使用新提交撤消已发布的提交
另一方面,如果您已发布作品,则可能不希望重置分支,因为这有效地重写了历史记录 . 在这种情况下,您确实可以还原提交 . 使用Git,revert有一个非常具体的含义:使用反向补丁创建一个提交以取消它 . 这样您就不会重写任何历史记录 .
git-revert manpage实际上在其描述中涵盖了很多内容 . 另一个有用的链接是this git-scm.com section discussing git-revert .
如果您决定不想还原,则可以还原还原(如此处所述)或重置为还原之前(请参阅上一节) .
在这种情况下,您可能会发现此答案很有用:
How to move HEAD back to a previous location? (Detached head)
尝试重置为所需的提交 -
git reset <COMMIT_ID>
(检查COMMIT_ID使用
git log
)这会将所有已更改的文件重置为未添加状态 .
现在你可以
checkout
所有未添加的文件了git checkout .
检查
git log
以验证您的更改 .UPDATE
如果您的仓库中有 one and only 提交,请尝试
git update-ref -d HEAD
将工作副本还原为最近的提交
要恢复到先前的提交,请忽略任何更改:
其中HEAD是当前分支中的最后一次提交
将工作副本还原为较旧的提交
要恢复到比最近提交更早的提交:
积分转到类似的Stack Overflow问题,Revert to a commit by a SHA hash in Git? .
这里有很多复杂而危险的答案,但实际上很简单:
这将从HEAD返回到提交哈希的所有内容,这意味着它将在工作树中重新创建该提交状态,就好像每次提交都已经被回退一样 . 然后,您可以提交当前树,它将创建一个全新的提交,基本上等同于您"reverted"的提交 .
(
--no-commit
标志允许git立即恢复所有提交 - 否则,系统会提示您为该范围内的每个提交发送一条消息,并使用不必要的新提交乱丢您的历史记录 . )这是 safe and easy way to rollback to a previous state . 没有历史被破坏,因此它可以用于已经公开的提交 .
恢复到最近的提交并忽略所有本地更改:
要保持从先前提交到HEAD的更改并移至上一次提交,请执行以下操作:
如果从先前提交到HEAD不需要更改并且只丢弃所有更改,请执行以下操作:
您可以通过以下两个命令执行此操作:
它将删除您之前的Git提交 .
如果您想保留更改,还可以使用:
然后它将保存您的更改 .
为了完全清除编码器目录中的一些意外更改,我们使用了:
只是
git reset --hard HEAD
将摆脱修改,但它赢得't get rid of 150843 files. In their case they' d意外地随机拖动一个重要的文件夹,所有这些文件被Git视为新的,所以reset --hard
没有修复它 . 通过预先运行git add -A .
,它使用git显式跟踪它们,以便通过重置消除 .我有类似的问题,并希望恢复到早期的提交 . 在我的情况下,我没有intetessered保持较新的提交,因此我使用
Hard
.这就是我做的方式:
这将在本地存储库上恢复,此后使用
git push -f
将更新远程存储库 .假设你正在谈论master和那个分支(也就是说,这可能是你所关注的任何工作分支):
我在博客文章Delete remote Git repo to specific commit找到了答案 .
选择所需的提交,然后进行检查
直到你得到所需的提交 . 为了使HEAD指向那个,做
或
git reset --hard HEAD~2
或其他什么 .我和其他人的最佳选择是Git重置选项:
这对我来说是最好的选择!它简单,快速,有效!
Note : 如评论中所述,don 't do this if you'与其他拥有旧提交副本的人分享您的分支
同样来自评论,如果你想要一个较少'ballzy'的方法,你可以使用
git clean -i
如果要“取消提交”,擦除最后一次提交消息,并将修改后的文件放回到分段中,则可以使用以下命令:
--soft
表示未提交的文件应保留为与--hard
相对的工作文件,这将丢弃它们 .HEAD~1
是最后一次提交 . 如果要回滚3次提交,可以使用HEAD~3
. 如果要回滚到特定的修订版号,也可以使用其SHA哈希来执行此操作 .在您提交了错误的内容并且想要撤消上次提交的情况下,这是一个非常有用的命令 .
资料来源:http://nakkaya.com/2009/09/24/git-delete-last-commit/
当你的提交被远程推送时,你需要删除它们 . 让我假设您的分支正在发展并且它被推到原点 .
首先需要从原点中删除develop:
然后你需要开发到你想要的状态,让我假设提交哈希是EFGHIJK:
最后,推动再次发展:
Revert是回滚提交的命令 .
样品:
git revert 2h3h23233
它能够从HEAD中获取范围,如下所示 . 这里1表示“还原最后一次提交” .
git revert HEAD~1..HEAD
然后做
git push
完成所有更改后,当您推送所有这些命令时,您可能必须使用:
而且不仅
git push
.有一个命令(不是核心Git的一部分,但它在git-extras包中)专门用于恢复和暂存旧提交:
根据man page,它也可以这样使用:
OK, 回到以前的git提交很容易......
还原 without keeping 更改:
还原 with keeping 更改:
Explain: 使用git reset,你可以重置为一个特定的状态,如上所述,它通常使用提交哈希 .
但正如您所看到的区别在于使用两个标志
--soft
和--hard
,默认git reset
使用--soft
标志,但这是一个很好的做法总是使用标志,我解释每个标志:--soft
解释的默认标志,不需要提供它,不会更改工作树,但添加准备提交的所有更改文件,因此您将返回到提交状态,更改为文件将被取消暂停 .
- 硬
小心这个标志,它会重置工作树以及对跟踪文件的所有更改,一切都将消失!
我还创建了下面的图像,可能发生在使用git的现实生活中:
假设您在名为
~/commits-to-revert.txt
的文本文件中有以下提交(我使用了git log --pretty=oneline
来获取它们)创建一个Bash shell脚本来还原每个脚本:
这会将所有内容还原回以前的状态,包括文件和目录创建以及删除,将其提交到您的分支并保留历史记录,但是您将其还原为相同的文件结构 . 为什么Git没有
git revert --to <hash>
超出我的范围 .我相信有些人可能会想要知道如何回滚他们在他们的主人身上做出的改变 - 即抛弃一切并返回原点/主人,在这种情况下,执行此操作:
https://superuser.com/questions/273172/how-to-reset-master-to-origin-master
我已经尝试了很多方法来恢复Git中的本地更改,如果你只想恢复到最新的提交状态,这似乎是最好的 .
简短的介绍:
它不会像
git revert
那样创建任何提交 .它不会像
git checkout <commithashcode>
那样分离你的头部 .它将覆盖所有本地更改并删除自分支中最后一次提交以来所有添加的文件 .
它仅适用于分支名称,因此您只能以这种方式恢复分支中的最新提交 .
我找到了一种更方便,更简单的方法来实现上述结果:
其中HEAD指向您当前分支的最新提交 .
它与boulder_ruby建议的代码相同,但是我在
git reset --hard HEAD
之前添加了git add .
以清除自上次提交以来创建的所有新文件,因为这是大多数人在恢复到最新提交时所期望的 .这是回到之前提交的一种 much simpler 方式(让它处于非公开状态,无论你喜欢什么,都可以使用它):
所以,不需要提交ID等等:)
如果要在上次提交中更正某些错误,则可以使用 git commit --amend 命令 . 如果任何引用都没有指向最后一次提交,那么这将起到作用,因为它创建一个与最后一次提交具有相同父级的提交 . 如果没有对最后一次提交的引用,它将被简单地丢弃,并且此提交将是最后一次提交 . 这是在不恢复提交的情况下纠正提交的好方法 . 但它有其自身的局限性 .
您可以自己完成所有这些初始步骤,然后再回到git repo .
使用
git pull --all
命令从Bitbucket中提取最新版本的存储库 .从终端运行带-n 4的git log命令 . -n之后的数字确定从本地历史记录中最近一次提交开始的日志中的提交数 .
$ git log -n 4
使用
git reset --hard HEAD~N
重置存储库历史记录的头部,其中N是您想要返回的提交数 . 在以下示例中,head将被设置为一次提交,以及存储库历史记录中的最后一次提交:使用
git push --force
将更改推送到git repo以强制推送更改 .如果你想要git存储库到以前的提交
如果情况是 urgent one ,并且您只想以 quick and dirty 方式执行提问者所要求的操作,假设您的项目位于目录"my project"下:
复制整个目录并将其称为其他内容,例如“我的项目 - 复制”
做:
然后,您的系统上有两个版本...您可以检查或复制或修改先前提交中感兴趣的文件或其他任何内容 . 你可以完全放弃“我的项目 - 复制”下的文件,如果你已经决定新的工作无处可去......
很明显,如果你想继续执行项目状态而不实际丢弃工作,因为这个检索到的提交是重新命名你的目录:删除包含检索到的提交的项目(或给它一个临时名称)并重命名你的“我的项目 - 将“目录复制回”我的项目“ . 然后可能很快就会做另一次提交 .
Git是一个出色的创作,但你不能只是"pick it up on the fly":也试图解释它的人 far too often 假设其他VCS [版本控制系统]的先前知识并且太快深入钻研,并犯下其他罪行,例如使用可互换的术语对于"checking out" - 有时看起来几乎可以混淆初学者的方式 .
为了节省很多压力,你必须要读一本关于Git的书 - 我推荐"Version Control with Git" . 如果你说"have to"时你可以信任我(或者更确切地说是我的伤疤),那么你可以这样做 NOW . Git的大部分复杂性来自分支然后重新合并 . 但是根据你的问题,有 no reason why people should be blinding you with science .
特别是如果,例如,这是一个绝望的情况,你是Git的新手!
PS:另一个想法:它(现在)实际上是相当的将Git存储库("repo")保存在除具有工作文件的目录之外的目录中 . 这意味着你不必使用上面的快速和脏的解决方案来复制整个Git存储库 . 请参阅Fryer使用--separate-git-dir here的答案 . Be warned ,但是:如果你有一个"separate-directory"存储库而你没有复制,并且你进行了硬复位,那么重置提交之后的所有版本将永远丢失,除非你绝对应该定期备份你的存储库,最好到 Cloud (例如Google Drive)等地方 .
Jefromi解决方案的额外替代品
Jefromi's solutions绝对是最好的,你绝对应该使用它们 . 但是,为了完整起见,我还想展示这些其他替代解决方案,这些解决方案也可用于恢复提交(在某种意义上,你 create a new commit that undoes changes in previous commit ,就像
git revert
所做的那样) .要清楚,这些替代方案 are not the best way to revert commits ,Jefromi's solutions are,但我只是想指出,您也可以使用这些其他方法来实现与
git revert
相同的功能 .备选1:硬重置和软重置
这是Charles Bailey对Revert to a commit by a SHA hash in Git?的解决方案的略微修改版本:
这基本上是通过使用软重置将使先前提交的状态在索引/暂存区域中暂存的事实来实现的,然后您可以提交该区域 .
备选2:删除当前树并替换为新树
这个解决方案来自svick的Checkout old commit and make it a new commit解决方案:
与备选#1类似,它会在当前工作副本中重现
<commit>
的状态 . 首先必须执行git rm
,因为git checkout
不会删除自<commit>
以来添加的文件 .除了这个确切的组合,这里没有任何东西对我有用:
这里的关键是强制推送,没有额外的提交/提交消息等 .
这是直接重置为最近提交的另一种方法
它直接清除自上次提交以来您所做的所有更改 .
PS:它有一点问题;它还会删除您最近存储的所有存储更改 . 在大多数情况下,我猜这应该不重要 .