revert某次提交 - git重置本地
如何将Git存储库还原为先前的提交 (20)
如何从当前状态恢复为在某个提交时创建的快照?
如果我做git log
,那么我得到以下输出:
$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <[email protected]>
Date: Thu Nov 4 18:59:41 2010 -0400
blah blah blah...
commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <[email protected]>
Date: Thu Nov 4 05:13:39 2010 -0400
more blah blah blah...
commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <[email protected]>
Date: Thu Nov 4 00:55:06 2010 -0400
And yet more blah blah...
commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <[email protected]>
Date: Wed Nov 3 23:56:08 2010 -0400
Yep, more blah blah.
如何从11月3日恢复提交,即提交0d1d7fc
?
警告!如果用户错误地提交了错误的提交,则此命令可能导致丢失提交历史记录。总是有你额外的git备份,以防万一你犯错误,比你更安全一些。 :)
我有类似的问题,并希望恢复到早期的提交。在我的情况下,我没有完全保持更新的提交因此我使用Hard
。
这就是我做的方式:
git reset --hard CommitId && git clean -f
这将在本地存储库上恢复,此处使用git push -f
后将更新远程存储库。
git push -f
Jefromi解决方案的额外替代品
Jefromi的解决方案绝对是最好的,你绝对应该使用它们。 但是,为了完整起见,我还想展示这些其他替代解决方案,这些解决方案也可用于恢复提交(在某种意义上,您创建一个新的提交,撤消先前提交中的更改 ,就像git revert
那样) 。
要清楚,这些替代方案并不是恢复提交的最佳方式 , Jefromi的解决方案是 ,但我只想指出,您也可以使用这些其他方法来实现与git revert
相同的功能。
备选方案1:硬重置和软重置
这是Charles Bailey 在Git中通过SHA哈希恢复提交的解决方案的略微修改版本? :
# Reset the index to the desired commit
git reset --hard <commit>
# Move the branch pointer back to the previous HEAD
git reset --soft [email protected]{1}
# Commit the changes
git commit -m "Revert to <commit>"
这基本上可以通过使用软重置将使先前提交的状态保留在索引/暂存区域中的事实来实现,然后您可以提交该区域。
备选方案2:删除当前树并替换为新树
这个解决方案来自svick对Checkout旧提交的解决方案, 并使其成为新的提交 :
git rm -r .
git checkout <commit> .
git commit
与备选#1类似,这将再现当前工作副本中<commit>
的状态。 首先需要执行git rm
因为git checkout
不会删除自<commit>
以来添加的文件。
将工作副本还原为最近的提交
要恢复到先前的提交,请忽略任何更改:
git reset --hard HEAD
其中HEAD是当前分支中的最后一次提交
将工作副本还原为较旧的提交
要恢复到比最近提交更早的提交:
# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced
# Moves pointer back to previous HEAD
git reset --soft [email protected]{1}
git commit -m "Revert to 56e05fced"
# Updates working copy to reflect the new commit
git reset --hard
Credits转到类似的问题, 在Git中恢复为SHA哈希的提交? 。
Revert是回滚提交的命令。
git revert <commit1> <commit2>
样品:
git revert 2h3h23233
它能够从HEAD中获取范围,如下所示。 这里1表示“还原最后一次提交”。
git revert HEAD~1..HEAD
然后做git push
为了完全清除编码器目录中的一些意外更改,我们使用了:
git add -A .
git reset --hard HEAD
只是git reset --hard HEAD
将摆脱修改,但它不会摆脱“新”文件。 在他们的情况下,他们意外地随机拖动了一个重要的文件夹,所有这些文件被Git视为新文件,所以reset --hard
没有修复它。 通过运行git add -A .
事先,它使用git显式跟踪它们,以便通过重置来消除它们。
假设你在一个名为~/commits-to-revert.txt
的文本文件中有以下提交(我使用git log --pretty=oneline
来获取它们)
fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca
创建一个Bash shell脚本来还原每个脚本:
#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
git revert $i --no-commit
done
这会将所有内容还原回以前的状态,包括文件和目录创建以及删除,将其提交到您的分支并保留历史记录,但是您将其还原为相同的文件结构。 为什么Git没有git revert --to <hash>
超出我的范围。
在回答之前,让我们添加一些背景,解释这个HEAD
是什么。
First of all what is HEAD?
HEAD
只是对当前分支上当前提交(最新)的引用。 在任何给定时间只能有一个HEAD
(不包括git worktree
)。
HEAD
的内容存储在.git/HEAD
,它包含当前提交的40字节SHA-1。
detached HEAD
如果你没有进行最新的提交 - 意味着HEAD
指向历史记录中的先前提交,则称为detached HEAD
。
在命令行上它看起来像这样 - SHA-1而不是分支名称,因为HEAD
没有指向当前分支的尖端:
关于如何从分离的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>
git reflog
您也可以随时使用reflog
。 git reflog
将显示更新HEAD
任何更改,并且检出所需的reflog条目会将HEAD
设置回此提交。
每次修改HEAD时, reflog
都会有一个新条目
git reflog
git checkout [email protected]{...}
这将使您回到所需的提交
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 2.7起 )您也可以使用
git rebase --no-autostash
。
此架构说明了哪个命令执行的操作。 如您所见, reset && checkout
修改HEAD
。
如果要“取消提交”,擦除最后一次提交消息,并将修改后的文件放回到分段中,则可以使用以下命令:
git reset --soft HEAD~1
-
--soft
表示未提交的文件应保留为与--hard
相对的工作文件,这将丢弃它们。 -
HEAD~1
是最后一次提交。 如果你想回滚3次提交,你可以使用HEAD~3
。 如果要回滚到特定的修订版号,也可以使用其SHA哈希来执行此操作。
在您提交了错误的内容并且想要撤消上次提交的情况下,这是一个非常有用的命令。
资料来源: http://nakkaya.com/2009/09/24/git-delete-last-commit/ : http://nakkaya.com/2009/09/24/git-delete-last-commit/
对于回滚(或恢复):
- git revert --no-commit“commit-code-to-remove”HEAD(例如git revert --no-commit d57a39d HEAD)
- git commit
- git push
尝试以上两个步骤,如果你发现这是你想要的那么git push。
如果你发现错误的话:
git revert --abort
尝试重置为所需的提交 -
git reset <COMMIT_ID>
(检查COMMIT_ID使用git log
)
这会将所有已更改的文件重置为未添加状态。
现在你可以通过checkout
所有未添加的文件
git checkout .
检查git log
以验证您的更改。
UPDATE
如果你有一个并且只在你的回购中提交,请尝试
git update-ref -d HEAD
您可以自己完成所有这些初始步骤,然后再回到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 push --force
送到git repo以强制推送更改。
如果你想要git存储库到以前的提交
git pull --all
git reset --hard HEAD~1
git push --force
您可以通过以下两个命令执行此操作:
git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f
它将删除您之前的Git提交。
如果您想保留更改,还可以使用:
git reset --soft [previous Commit SHA id here]
然后它将保存您的更改。
我已经尝试了很多方法来恢复Git中的本地更改,如果你只想恢复到最新的提交状态,这似乎是最好的。
git add . && git checkout master -f
简短的介绍:
- 它不会像
git revert
那样创建任何提交。 - 它不会像
git checkout <commithashcode>
那样分离你的HEAD。 - 它将覆盖所有本地更改并删除自分支中最后一次提交以来所有添加的文件。
- 它仅适用于分支名称,因此您只能以这种方式恢复分支中的最新提交。
我找到了一种更方便,更简单的方法来实现上述结果:
git add . && git reset --hard HEAD
其中HEAD指向您当前分支的最新提交。
它与boulder_ruby建议的代码相同,但我添加了git add .
在git reset --hard HEAD
之前git reset --hard HEAD
擦除自上次提交以来创建的所有新文件,因为这是大多数人在恢复到最新提交时所期望的。
我相信有些人可能会想要知道如何回滚他们在他们的主人身上做出的改变 - 即抛弃一切并返回原点/主人,在这种情况下,执行此操作:
git reset --hard origin/master
https://superuser.com/questions/273172/how-to-reset-master-to-origin-master
要保持从先前提交到HEAD的更改并移至上一次提交,请执行以下操作:
git reset <SHA>
如果从先前提交到HEAD不需要更改并且只丢弃所有更改,请执行以下操作:
git reset --hard <SHA>
这很大程度上取决于“恢复”的含义。
暂时切换到其他提交
如果你想暂时回到它,傻瓜,然后回到你所在的位置,你所要做的就是检查所需的提交:
# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32
或者,如果你想在那里做出提交,那么在你做的时候继续做一个新的分支:
git checkout -b old-state 0d1d7fc32
要回到原来的位置,只需查看您再次访问的分支。 (如果你做了更改,就像转换分支时一样,你必须在适当的时候处理它们。你可以重置它们扔掉它们;你可以藏匿,结账,存放pop以带走它们;你可以提交如果你想要那里的分支,他们到那里的一个分支。)
硬删除未发布的提交
另一方面,如果你想真正摆脱自那时以来所做的一切,那么有两种可能性。 一,如果您还没有发布任何这些提交,只需重置:
# 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,revert有一个非常具体的含义:使用反向补丁创建一个提交以取消它。 这样您就不会重写任何历史记录。
# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053
# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD
#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053
# Reverting a merge commit
git revert -m 1 <merge_commit_sha>
# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .
# Then commit. Be sure and write a good message describing what you just did
git commit
git-revert
页实际上在其描述中涵盖了很多内容。 另一个有用的链接是这个讨论git-revert的git-scm.com部分 。
如果您决定不想还原,则可以还原还原(如此处所述)或重置为还原之前(请参阅上一节)。
在这种情况下,您可能会发现此答案很有用:
如何将HEAD移回以前的位置? (独立头)
这里有很多复杂而危险的答案,但实际上很简单:
git revert --no-commit 0766c053..HEAD
git commit
这将从HEAD返回到提交哈希的所有内容,这意味着它将在工作树中重新创建该提交状态, 就好像每次提交都已经被回退一样。 然后,您可以提交当前树,它将创建一个全新的提交,基本上等同于您“恢复”的提交。
( --no-commit
标志允许git立即恢复所有提交 - 否则,系统会提示您为该范围内的每个提交发送一条消息,并使用不必要的新提交乱丢您的历史记录。)
这是回滚到以前状态的安全且简单的方法 。 没有历史被破坏,因此它可以用于已经公开的提交。
选择所需的提交,然后进行检查
git show HEAD
git show HEAD~1
git show HEAD~2
直到你得到所需的提交。 为了使HEAD指向那个,做
git reset --hard HEAD~1
或者git reset --hard HEAD~2
或者其他什么。
如果你想在最后一次提交中纠正一些错误,那么一个好的选择就是使用git commit --amend命令。如果任何引用都没有指向最后一次提交,那么这将起到作用,因为它创建一个与最后一次提交具有相同父级的提交。如果没有对最后一次提交的引用,它将被简单地丢弃,并且此提交将是最后一次提交。这是在不恢复提交的情况下纠正提交的好方法。但它有其自身的局限性。
如果情况紧急,你只是想以快速而肮脏的方式做提问者的问题,假设你的项目在“我的项目”目录下:
复制整个目录并将其称为其他内容,例如“我的项目 - 复制”
做:
git reset --hard [first-4-letters&numbers-of-commit's-SHA]
然后,您的系统上有两个版本...您可以检查或复制或修改先前提交中感兴趣的文件或其他任何内容。你可以完全放弃“我的项目 - 复制”下的文件,如果你已经决定新的工作无处可去......
很明显,如果你想继续执行项目状态而不实际丢弃工作,因为这个检索到的提交是重新命名你的目录:删除包含检索到的提交的项目(或给它一个临时名称)并重命名你的“我的项目 - 将“目录复制回”我的项目“。然后可能很快就会做另一次提交。
Git是一个出色的创作,但你不能只是“随时拿起它”:试图解释它的人也经常假设其他VCS [版本控制系统]的先验知识,并且过早地钻研太深,并且犯下其他罪行,比如使用可互换的术语来“退出” - 这种方式有时似乎几乎可以使初学者感到困惑。
为了节省很多压力,你必须要读一本关于Git的书 - 我建议使用Git进行版本控制。如果你能信任我(或者更确切地说,我的伤疤),当我说“有”,它遵循你还不如做NOW。Git的大部分复杂性来自分支然后重新合并。但是从你的问题来看,没有理由为什么人们应该用科学让你眼花缭乱。
特别是如果,例如,这是一个绝望的情况,你是Git的新手!
PS:另一个想法:将(现在)将Git存储库(“repo”)保存在除工作文件之外的目录中实际上非常简单。这意味着你不必使用上面的快速和脏的解决方案来复制整个Git存储库。使用--separate-混帐目录见油炸答案here。但是要注意:如果你有一个你没有复制的“单独目录”存储库,并且你进行了硬复位,那么重置提交之后的所有版本将永远丢失,除非你有绝对应该的,定期备份您的存储库,最好是其他地方的云(例如Google Drive)。