如何从当前状态恢复到某个提交时创建的快照?
如果我执行git log,那么我得到以下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| $ 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提交?.
- 这里有一篇非常清晰和彻底的关于撤销Git中的事情的文章,直接从Github开始。
- 相关:回滚到公共回购中的旧git提交。注意,这个问题增加了回购是公开的限制。
- 我喜欢Git,但有35个答案是非常简单的,这就暴露了Git的一个大问题。还是医生?
- 他们可以为历史上的SVN添加按钮功能。
- 语言"陷阱"是如何使用这个词还原为口语意义重置甚至没有解决这里????到目前为止,有6594张赞成票,而不是用这种方式编辑,以强调区别?在这里使用表达式"提交"来引用"保存文件"不会更令人困惑…
这很大程度上取决于你所说的"还原"。
临时切换到其他提交
如果你想暂时回到原来的状态,那就绕过去,然后回到原来的状态,你所要做的就是检查一下你想要的承诺:
1 2
| # This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32 |
或者,如果你想在那里的时候做出承诺,那就在那里做一个新的分支吧:
1
| git checkout -b old-state 0d1d7fc32 |
要回到原来的位置,只需再次查看您所在的分支。(如果你已经做出了改变,像往常一样在切换分支时,你必须适当地处理它们。您可以重新设置以丢弃它们;您可以隐藏、结帐、存储弹出窗口以随身携带它们;如果您希望在那里建立分支,您可以将它们提交到那里的分支。)
硬删除未发布的提交
另一方面,如果你真的想摆脱自那以后所做的一切,有两种可能性。第一,如果您没有发布任何这些提交,只需重置:
1 2 3 4 5 6 7 8 9 10 11
| # 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有一个非常具体的含义:使用reverse补丁创建一个commit来取消它。这样你就不会重写任何历史。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| # 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-scm.com部分,讨论git还原。
如果您决定根本不想还原,可以还原还原(如此处所述)或重置回还原之前的状态(请参阅上一节)。
在这种情况下,您也会发现这个答案很有用:如何将头部移回以前的位置?(分离头)
- 我尝试了你的第一种方法,但当我回到master并尝试合并新的分支时,它说Already up-to-date.。我通过将文件从新的分支复制到和外部文件夹,检查master back out,然后手动将文件复制回overwrite everything,然后是git adding和git commiting everything to master来解决我的问题。之后,我删除了新的(但暂时的)分支。
- 只有一件事…我怎么才能回到正题上来?在执行git checkout 0d1d7fc32之后??
- @"头"的意思是"我以前检查过的分支机构"?git checkout -检查了以前认为您已经检查过的;git checkout 将是明确的方法。(和这里关于git的任何内容一样,如果您不理解命令的作用,请小心运行命令。)
- 在头上,我说的是我以前的承诺,最后的承诺
- 你可能已经签出了一个分支,而不仅仅是一个承诺——而且在你故意再次分离head之前,你应该理解其中的区别。
- @Rod对git revert HEAD~3是恢复3承诺的最好办法的评论是一个重要的惯例。
- 你能把整个数字写下来吗?比如:git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50。
- @MathiasMadsenstav是的,您当然可以通过完整的sha1指定提交。我使用了缩写的散列来提高答案的可读性,如果你在打字,你也倾向于使用它们。如果您正在复制和粘贴,那么一定要使用完整的哈希。有关如何命名提交的完整描述,请参见在man git rev parse中指定修订。
- 我运行"git checkout 0d1d7fc32"暂时返回。现在我该如何回到最新的情况?我的最新消息不再出现在"Git日志"中
- 要返回到当前状态,命令是"git checkout master"
- 您可以使用git revert --no-commit hash1 hash2 ...,然后只需在一个commit git commit -m"Message"中提交每个还原。
- 你需要在恢复后做一个git push origin master。
- Git社区图书链接已失效。这是个好的替代品吗?git-scm.com/book/en/git-basics-undoing-things
- 不要错过范围(从..到),如git revert HEAD~2..HEAD所示。发生。。。
- 为什么使用git stash && git reset --hard && git stash pop?git reset 0d1d7fc32不会实现同样的目标吗?--mixed是reset的默认值,它使工作树与重置前一样保持未分页状态。
- @如果一些修改在必须重置的文件中(它们在提交中被更改,将在重置中丢失),则Gregers不会。
- @Jameskinsbery没有提到"Git Revert"。
- 难道江户十一〔16〕不是江户十一〔17〕吗?
- @在手册页顶部的用法说明中,改为:git checkout [-b ] []。你所写的也可能有效,但是它不是选项和参数的正常顺序,而且它没有被记录为有效。
- 顺便说一句,如果您创建了一些文件,然后重置,请确保运行git clean -f -d -n查看哪些文件没有被跟踪,并运行git clean -f -d删除它们。
- 在这种情况下,"发布"是什么意思?
- @雅林的回答更安全。在决定做什么之前,请先看一下。
- @无论安全与否,这都不是那么简单;答案并不都是一样的。雅林的答案是这个答案中最后一个选项的特例。
- 由于OP没有指定S/HE是否需要临时/未发布/已发布的还原,因此您的答案肯定是完整的,我将其否决。但Yarin接近第三个选项的简单方法是imho更好地使用、记住和避免错误。简单就是好。
- 示例我做了3次提交,c1 c2 c3是这样的,现在我意识到在c1之后我所做的一切都是垃圾,所以我想回到那个状态,并远程提交c1,即文件状态应该是。还原到c1和git日志应该只显示c1和更旧的提交,使用git reset——硬c1id将是完美的?…谢谢,我是个新手
- 还要注意,如果提交上有任何标记,您试图删除这些标记,您将希望使用git tag -d some-tag-name删除它们。
- 你怎么从git checkout 0d1d7fc32返回头部?假设我最近提交的是0D1D85932。我执行了git checkout 0d1d7fc32,但现在我想回到原来的位置。如果我执行git checkout 0d1d85932,git说是分离的头。谢谢
- 那么,在执行"git checkout 0d1d7fc32"之后,有人能告诉我如何返回到最新的提交吗??
- @tyegah123@mannuk型git checkout master。
- 我不明白你对格雷格的解释。即使提交中的某些文件更改为丢失,它们的副本仍在工作树中。我不知道在"硬删除未发布的提交"而不是简单的git reset --mixed的情况下,存储什么时候有用。
- 临时切换到其他提交-如何切换回?
- @Donhatch也许是因为这不是问题所在,完全回答会增加更多的复杂性,而简单的回答基本上是"再做一次"。例如,如果您使用git revert,那么决定您不想这样做,返回到您之前所在的位置就相当于再次执行此答案中的一项操作-还原还原、重置为还原之前的位置,或签出为还原之前的位置。我可以编辑一点,但是如果你有不同的问题,可以问一个新的问题。
- 我看到你改进了答案,使它更接近广告,谢谢:-)这确实使你的答案更有用,对我来说,它看起来,对其他几个在这个线程中评论的人。我认为如果能让这部分配方更明确一点,它可能会得到更大的改进,特别是对于一个新的/临时的用户来说,不一定很明显他们现在有一个叫做"master"的分支被签出。建议:"要回到原来的位置,只需使用git checkout -或明确的分支名称(如‘master’)再次检查您所在的分支即可。"
- 注意,在Gitlab或Github上使用硬重置时,不要忘记"取消保护"您的分支。
- @jefromi,在"git checkout 0d1d7fc32."之后,头部是否已经分离?那么"git-commit"就不能用悬空的头做任何事情。
- @用户1914692不,这不会分离头部。.有很重要的一点——它指示git从当前目录中的0d1d7fc32中检查状态,但它会将head留在原来的位置。这与使用类似于git checkout other-branch path/to/file的东西是一样的——它会将您留在当前的分支上,只需查看给定的文件即可。在本例中,我们将签出整个当前目录,而不是只签出一个文件,但仍然不更改head。
- @Jefromi谢谢。这是一个非常有用的选择。当Git Manual谈到"Git Checkout Commit"时,似乎没有提到要添加"."以避免头部分离。您的信息是否来自以下部分:"git checkout[-p--patch][][--]…?"?
- @用户1914692是的,.是一条路径。git checkout手册页中关于签出特定路径的任何内容都适用于此,包括您引用的第一句话:"当给定或--patch时,git checkout不会切换分支。"
- @杰弗洛米手册上写着"…不切换分支"。但它并没有说它不会分离头部。在link stackoverflow.com/question s/33656072/&hellip;中看到我的问题,有人说:"如果您想签出一个不是任何分支最后一次提交的提交,那么在同时让head引用分支时,根本不可能签出这个提交。"
- @用户1914692 Detaching Head是交换分支的子类别。当你分离头部时,你会把在一个分支上变成不在任何分支上。切换到分支和分离头之间的区别是目的地不同,但您仍然从当前分支切换开。所以当那个段落说它不切换分支时,它意味着head保持不变——如果您执行git checkout ,它不会切换到那个分支;如果您执行git checkout ,它不会通过切换到那个commit来分离head。
- @用户1914692当然,这与您所指的其他问题完全一致。如果不分离head,仍然无法实际签出非分支提交。您可以像这样检查提交的所有内容,但head仍然在原来的位置。如果你再次承诺,你将在你之前所在的位置上承诺,而不是其他承诺。实际上您还没有签出另一个提交。
- @杰弗洛米,我现在很困惑。你说"git checkout它不会通过切换到该commit来分离head"。然后您说"如果不分离head,仍然没有办法实际检查非分支提交。"
- 让我们在聊天中继续讨论。
- 正如答案中所描述的,我回到了以前的提交:git checkout 0d1d7fc32,然后我就开始胡思乱想,现在Git不让我回来了:您对以下文件的本地更改将被签出覆盖:quick2/viewcontroller.swift请提交您的更改或在您切换分支之前将其保存。堕胎——我怎么回来?
- @7stud答案与在其他情况下切换分支时收到的消息完全相同,但是我继续进行了简短的编辑以解决这个问题。如果您对如何切换分支感到困惑,那么可能需要问一个新问题。
- @Jefromi,如果我创建一个分支来愚弄别人,那么当我完成任务后,我将切换回master,然后删除该分支:git branch -D fool_around,当我返回到以前的任务并愚弄别人时,该如何工作?
- 如果要删除分支,为什么要提交?只需重置。但是,如果您更喜欢提交,然后通过删除分支而失去提交的跟踪,那么可以。您也可以这样做,而不必有分支;当您切换到别处时,您将失去对提交的跟踪。(这就是为什么有各种关于超人头的警告和帖子的原因——你在某个地方没有分支来跟踪它。)
- @Jefromi,如果你要删除分支,为什么要承诺?--这是我唯一知道怎么做的方法。:(无论如何,我仍然需要知道在签出以前的提交之后如何返回。如果你已经做出了改变,就像通常在切换分支时那样,你必须在适当的时候处理它们。你可以重新设置把它们扔掉——我该怎么做?
- @7stud git-scm.com/docs/git-reset或stackoverflow.com/questions/2530060/&hellip;
- 让我们在聊天中继续讨论。
- @如果你在master上,tyegah123 git checkout master是正确的。通常,您可以执行git checkout以返回最近的提交。如果在旧的提交中进行更改,然后尝试返回到master,它将告诉您将这些更改保存到新分支中或转储它们并返回到最新的代码的命令。
- 我只是使用git reset——硬0D1D7FC32
- git push -f origin master用于在本地修复后修复远程。
- 只需注意,如果您在合并或常规更改时搞砸了事情,您将注意到您不能只做上述操作。你首先需要提交你的问题文件。只是不要用力。
- @杰弗洛米如果我想重写历史怎么办,因为我再也不需要这些改变了。我需要返回三次提交,我不想在所需提交之前有任何内容?我是回购协议中唯一的一个,所以它不会影响任何其他人。在提交之前,我应该使用什么命令来丢弃所有的更改?
- @Alexventura有一个叫做"硬删除未发布的提交"的部分。
- @Jefromi没有,但是他们已经出版了。我是说他们在偏僻的地方。因为我已经运行了git push origin master,但是现在我想删除本地的de las三个提交,然后将更改推到远程,也可以完全删除所需提交前面的任何提交。
- @Alexventura听起来你已经知道你需要做这个了,然后推。如果你尝试过,你应该会得到一个关于非快速前进的错误,你可以用git push --force覆盖它。关于这一点,现有的问题很多,例如stackoverflow.com/q/10510462/119963 stackoverflow.com/q/6310208/119963 stackoverflow.com/q/10298291/119963
- @Jefromi是的,我已经按照你说的做了,我得到了那个错误,然后我使用了force。但是因为我对Git没有太多的经验,我不完全相信,所以我想知道这是正确的方法,还是有一种方法来确认并确保在我的实际承诺之前没有任何东西,只是在本地和远程覆盖去历史?
- @亚历克文图拉,我认为你已经到了该问一个新问题的地步了。这里的评论是为了澄清现有的答案。如果您需要帮助检查存储库的内容,或者哪些分支上有哪些提交,那么这是另一个主题。
- 三个部分,没有一个有用。真正的答案是:git revert——no commit 0766c053..head
- git checkout -b old-state 0d1d7fc32给了我一个错误,fatal: Cannot update paths and switch to branch 'oldApi' at the same time.我必须先打git checkout 0d1d7fc32然后打git checkout -b old-state来分别做。
- 我很肯定,问题是如何将存储库移回提交时的状态。因此,特别是Git的问题需要运用适度来对抗在知识和错综复杂的展示中过度告知的诱惑。问题很清楚:如果要在A、B、C分支之间切换,则不使用x、y、z返回,只要p、q、r、s。1个分支,1个问题,1个时间点返回。
- @乔丹斯特凡内利说实话,即使从你的评论来看,我也不知道你认为OP会想要哪种选择。我当然不认为这是一个明确的行动,希望-"还原"可以有很多不同的含义,似乎知识的一些选择,其中每一个可能是正确的选择,在不同的情况下,将有助于行动以及未来的读者。我敢说,接受和赞成票已经证明了这一点。
- 提交范围特别有用。谢谢!
- 那么,如果我只想恢复上一次发布的提交,我可以通过git revert HEAD完成吗?
正在将工作副本还原为最新提交
要恢复到以前的提交,忽略任何更改:
其中head是当前分支中的最后一个提交
将工作副本还原为旧提交
要恢复到比最新提交早的提交,请执行以下操作:
1 2 3 4 5 6 7 8 9 10
| # Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced
# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}
git commit -m"Revert to 56e05fced"
# Updates working copy to reflect the new commit
git reset --hard |
学分转到一个类似的堆栈溢出问题,在git中通过sha散列返回到commit?.
- 我做到了,但后来我无法提交并推送到远程存储库。我想让一个特定的老年人成为领袖…
- 这意味着你已经推进了你想要恢复的承诺。它可以为那些已经签出代码并正在处理代码的人带来很多问题。因为他们不能把你的承诺顺利地应用到他们身上。在这种情况下,最好执行git还原。如果你是唯一一个使用回购协议的人。做一个git push-f(但在做之前要三思)
- 强制性警告:如果您与其他拥有旧提交副本的人共享您的分支,请不要硬重置,因为使用这样的硬重置会迫使他们必须将其工作与新重置的分支重新同步。不过,软重置是安全的,也是这个答案中的最后一个解决方案。
- 我还想指出,对于软重置解决方案,您可以先执行硬重置,而不是先执行混合重置,再执行硬重置,具体如下:git reset --hard 56e05fc; git reset --soft HEAD@{1}; git commit。
- 如果您在PowerShell中工作,请在head@1:git reset--Soft'head@1'周围添加引号,因为大括号有意义
- 遗憾的是,版本控制系统使基本历史浏览aciton的语法变得如此复杂。
- @吉特的创建者纳顿·林纳斯·保林本人也批评它过于复杂。他有记录地说他"震惊"Git因为其复杂性变得如此受欢迎
- 它让我使用维姆,我不知道怎么…太令人沮丧了。
- @PixelFairy,为了避免不得不这样做,请使用-m标志和括号中的字符串作为提交注释,如:git commit -a -m 'commit message'所示。
- 为什么不只是:git reset—hard"(较旧的commit)"?
- @goldname只做硬重置对本地来说很好,但是在github上的远程商店就崩溃了。由于落后,你无法在没有拉的情况下更新(这会破坏目标)。软/硬重置组合肯定是我的首选,因为它解决了这个问题!
- 这个答案很糟糕,因为它不"起作用"。从简单的意义上说,重置会改变本地工作副本中的更改,但随后它会说您在卡车后面提交了1个。只是一个灾难的药方。
- @博尔德·鲁比,我想你的意思是莱纳斯·托瓦尔兹是Git的创造者。但我认为,保林可能会同意吉特是复杂的。
- 非常感谢@bolder_ruby!
这里有很多复杂和危险的答案,但实际上很简单:
1 2
| git revert --no-commit 0766c053..HEAD
git commit |
这将把所有内容从头部还原到提交哈希,这意味着它将在工作树中重新创建提交状态,就好像从那时起的每个提交都被退回了。然后您可以提交当前树,它将创建一个全新的提交,本质上相当于您"恢复"到的提交。
(--no-commit标志允许Git一次恢复所有提交—否则将提示您为该范围内的每个提交发送一条消息,并将不必要的新提交丢弃在您的历史记录中。)
这是一种安全、简单的回滚到以前状态的方法。历史不会被破坏,所以它可以用于已经公开的提交。
- 如果您真的想要有单独的提交(而不是用一个大的提交来恢复所有内容),那么您可以通过--no-edit而不是--no-commit,这样您就不必为每次恢复编辑提交消息。
- 如果0766c053..head之间的一个提交是合并,则会弹出一个错误(与未指定-m的情况有关)。这可能有助于遇到以下情况:stackoverflow.com/questions/5970889/&hellip;
- GitNewbie这里:如果您不能使用这个命令返回到最近的提交:我收到一条"空提交"消息。所以您必须提交最新的工作,然后使用这个命令。我想知道是否有一种方法可以重置为最后一次提交?
- 要在提交之前查看差异,请使用git diff --cached。
- 这没有帮助;有一个合并,它弹出一个错误,说-m选项没有指定;在注释中,我做了这个git revert-m 1 head,然后重试,但它给出了一个错误,说cherrypick或revert正在进行中。我做了CherryPick——退出,它返回到消息,有一个合并,并且没有指定-m
- 我刚刚签出了提交散列,并在那里创建了一个新的分支来工作;这样更安全更容易
- 另外,我发现我需要使用-m"...."在命令行中指定消息,否则它将尝试打开vim,并且无法保存和破坏所有内容。
- $ git revert --no-commit 53742ae..HEAD返回fatal: empty commit set passed。
- 这是这个问题的最佳答案,它帮助我在完全恢复代码到其他树之后创建一个提交。
- 事实上,@celeritas,我对git的一个问题(除此之外我绝对喜欢)是,在一个未被注意到的错误提交/推之后,单一的回复(逻辑上)执行起来非常复杂。只有几条命令行,但非常危险…-)
- 如果您不想承诺(只是恢复状态),您应该使用:git revert --no-edit 6e286400dbe..HEAD、git reset --hard 6e286400dbe,这样您的本地回购将恢复到承诺状态6e286400dbe。
- @Alexg那是因为你需要在你想要返回的哈希值之前输入哈希值。在我的例子中,hashes是这样的:81bcc9e HEAD{0}; e475924 HEAD{1}, ...(来自git reflog),我想撤销我在81bcc9e中所做的,然后我不得不做git revert e475924..HEAD。
- 很多答案,很多案例,但看到人们称"恢复"选项更容易、更安全,我感到很沮丧。不是。它们是两个不同的用例。在具有不同分支的任何回购中-如果重置分支,则更改最终将在任何地方结束,即使是在重置的分支中(一旦分支涉及合并);如果还原更改,则更改最终将在任何地方删除,而不仅仅是此分支。如果不需要,这肯定不安全。
- @cookie——不遵循你的论点,或者你所说的"如果你恢复一个改变,改变最终会被删除到任何地方"。使用REVERT的优点是不删除任何内容,而使用RESET则是。这就是为什么它更安全。
- 在分支A中实现功能A。将其合并到主控形状。测试它。合并其他内容。将分支A合并到发布中。意识到你还不想释放它。放回原处。释放再次良好。合并发布到主功能A不存在。将分支A合并为主分支。将任何内容合并到主控形状。它仍然不见了。最后决定释放它。合并分支A以释放。功能A仍然不见了。它到处都不见了,唯一能让它恢复原状的方法就是全力以赴,或者恢复原状,这是一种痛苦。需要重置时不要还原。
- "是合并,但未提供-m选项。"
- 在我看来,对git revert --no-commit最好的方法是git diff > my-diff; patch -R -t -p1 < my-diff。这种方法不存在关于-m option was given的问题,也没有破坏历史。
- 这会产生一个错误:错误:commit d85f9b88d是一个合并,但没有给出-m选项。致命:还原失败
- 感谢你不是一个愚蠢的白痴,而是发布一个适用于大多数场景的有用回复。
对我和其他人来说,最好的选择是git重置选项:
1
| git reset --hard <commidId> && git clean -f |
这是我最好的选择!它简单、快速、有效!
注意:正如评论中提到的,如果您与其他拥有旧提交副本的人共享您的分支,则不要这样做。
另外,从评论中,如果你想要一个不那么"疯狂"的方法,你可以使用
git clean -i
- 强制性警告:如果您与其他拥有旧提交副本的人共享您的分支,请不要这样做,因为使用这样的硬重置会迫使他们必须将其工作与新重置的分支重新同步。有关详细解释如何在不丢失硬重置工作的情况下安全地还原提交的解决方案,请参阅此答案。
- 我附和了@cupcake的警告…非常清楚后果。但是,请注意,如果您真正需要使这些提交永远从历史中消失,那么这个重置+清除方法将做到这一点,并且您需要强制将修改过的分支推回到任何和所有远程。
- 记住,clean将删除.idea(phpsorm)或.vagrant(vagrant)等文件/文件夹,这些文件/文件夹可能由您的set/ide使用!
- Git清洁-F危险危险
- @Pogrindis-这里有很多不错的答案,不会删除未跟踪的文件。
- 如果您使用"git clean-f",我建议您首先检查将要删除的内容:git clean-f-n
- 这会将本地副本的头设置为所需的提交。但是我不能推动任何改变,因为它在遥控器后面。如果我从远程提取,它最终会返回到远程分支上最新提交的位置。我怎样才能完全抹掉(从任何地方)我的本地副本上被推掉的几项承诺呢?
- 阿德。您可以使用git push -f标志。但要小心,它会覆盖遥控器。一定要知道你想做什么…….
- 只与clean -f一起工作。我不需要保存我的任何工作。我也不想登记任何东西。我只是想恢复到以前的提交,因为构建在那时已经通过了。
在回答之前,让我们添加一些背景,解释这个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没有指向当前分支的尖端:
关于如何从分离的头部恢复的几个选项:
git checkout
1 2 3
| git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back |
这将签出指向所需提交的新分支。此命令将签出到给定的提交。
此时,您可以创建一个分支并从此处开始工作:
1 2 3 4 5 6 7 8
| # 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设置回此提交。
每次修改磁头时,reflog中都会有一个新条目。
1 2
| git reflog
git checkout HEAD@{...} |
这将使你回到你想要的承诺
git reset HEAD --hard "移动"你的头回到想要的承诺。
1 2 3 4 5 6 7 8 9 10 11
| # 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。
- 给EDOCX1[1]很好的暗示,这正是我需要的。
- 哎哟!这一切看起来非常复杂…难道没有一个简单的命令可以让您在这个过程中后退一步吗?比如从项目的1.1版回到1.0版?我期待着这样的事情:吉特后退一步,一个承诺或什么…
- 有:git reset HEAD^——硬的`
- @Kokodoko是的,它非常复杂…这是一个完美的例子,说明专家们对刚起步的人的考虑是多么的少。请参阅我这里的答案,以及我推荐的那本书。Git并不是你能凭直觉得到的东西。我可以肯定的是,代码向导没有这样做。
如果要"取消提交",请清除最后一条提交消息,并将修改后的文件放回临时状态,则将使用以下命令:
- --soft表示未提交的文件应保留为工作文件,而不是将其丢弃的--hard。
- HEAD~1是最后一次提交。如果要回滚3个提交,可以使用HEAD~3。如果要回滚到特定的修订号,也可以使用其sha散列进行回滚。
这是一个非常有用的命令,在您提交了错误的事情并且希望撤消最后一次提交的情况下。
来源:http://nakkaya.com/2009/09/24/git-delete-last-commit/
我尝试了很多方法来恢复Git中的本地更改,如果您只想恢复到最新的提交状态,这似乎是最好的方法。
1
| git add . && git checkout master -f |
简短描述:
- 它不会像git revert那样产生任何承诺。
- 它不会像git checkout 那样分开你的头。
- 它将覆盖所有本地更改,并删除自上次提交分支以来添加的所有文件。
- 它只与分支名称一起工作,因此您只能以这种方式在分支中恢复到最新的提交。
我找到了一种更方便和简单的方法来实现上述结果:
1
| git add . && git reset --hard HEAD |
其中head指向当前分支的最新提交。
它与boulder_Ruby建议的代码相同,但我在git reset --hard HEAD之前添加了git add .以删除自上次提交以来创建的所有新文件,因为这是大多数人在恢复到最新提交时所期望的。
您可以通过以下两个命令执行此操作:
1 2
| git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f |
它将删除您以前的Git提交。
如果要保留更改,还可以使用:
1
| git reset --soft [previous Commit SHA id here] |
然后它将保存您的更改。
- 我在这篇文章里试了1/2打答案,直到找到这个。其他的,我的Git配置在尝试推送时一直给我一个错误。这个答案奏效了。谢谢!
- 对我来说,一个细节是我失去了差异。我想继续看看我在承诺中做了些什么,但没有奏效。所以下次我会在发出这个重置命令之前保存数据
- 这是我撤消错误合并的唯一方法,Revert在这种情况下不起作用。谢谢!
好吧,回到Git上一次提交非常简单…
在不保留更改的情况下还原:
1
| git reset --hard <commit> |
保留更改后还原:
1
| git reset --soft <commit> |
解释:使用git reset,你可以重置到一个特定的状态,这是常见的使用它与提交散列,如你所见。
但是,正如您所看到的,区别在于使用两个标志--soft和--hard,默认情况下,git reset使用--soft标志,但始终使用该标志是一个很好的做法,我解释每个标志:
--软
如前所述,不需要提供默认标志,它不会更改工作树,而是添加所有已准备好提交的更改文件,因此您将返回到提交状态,对文件所做的更改将被取消。
--硬
小心这个标志,它会重置工作树,所有对跟踪文件的更改都会消失!
我还创建了下面的图片,在现实生活中使用Git时可能会发生这种情况:
除了这个确切的组合,这里没有什么对我有用的:
1 2
| git reset --hard <commit_hash>
git push origin <branch_name> --force |
这里的关键是强制推送,没有额外的提交/提交消息等。
- 这对我很有效,但您需要小心,因为硬重置之后的所有提交历史记录都将丢失,并且此操作是不可逆的。你必须确定你在做什么。
假设您在名为~/commits-to-revert.txt的文本文件中有以下提交(我使用git log --pretty=oneline获取它们)
1 2 3 4 5 6 7 8 9 10 11
| fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca |
创建一个bash shell脚本来恢复它们:
1 2 3 4 5 6
| #!/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 是我无法理解的。
- 你可以做一个git revert HEAD~3来删除最后3个提交
- @罗德-不,那不对。该命令将恢复头的第三个祖父母的提交(而不是最后三个提交)。
- @好的,谢谢你的信息。江户十一〔九〕行吗?(如kernel.org/pub/software/scm/git/docs/git revert.html所示)
- @罗德-听起来不错,当然是一个丑陋的语法,不是吗?我总是发现检查我想要"恢复"到的提交,然后更直观地提交。
- @肯洛伦斯不需要你做一个新的分支吗?
- @兰斯,我同意你关于Git还原-到-这似乎是一个令人难以置信的复杂的方式来实现相当简单的事情!
- @不,不需要创建一个新的分支。
- 现在有一种比使用这样的脚本更简单的方法,只需使用git revert --no-commit ..,因为git revert接受新的(或全部)提交范围。Git的版本。请注意,范围的开始不包括在还原中。
Jefromi解决方案的额外替代方案
Jefromi的解决方案绝对是最好的,你应该使用它们。但是,为了完整性起见,我还想展示这些其他可选的解决方案,这些解决方案也可以用于恢复提交(从某种意义上说,您创建了一个新的提交来撤销以前提交中的更改,就像git revert所做的那样)。
显然,这些替代方案不是恢复承诺的最佳方法,Jefromi的解决方案是,但我想指出的是,您也可以使用这些其他方法来实现与git revert相同的事情。
备选方案1:硬重置和软重置
这是CharlesBailey的解决方案的一个非常小的修改版本,它可以通过git中的sha散列返回到commit?:
1 2 3 4 5 6 7 8
| # Reset the index to the desired commit
git reset --hard <commit>
# Move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}
# Commit the changes
git commit -m"Revert to <commit>" |
这基本上是通过使用软重置将上一次提交的状态保留在索引/临时区域中,然后您可以提交这一事实来实现的。
备选方案2:删除当前树并替换为新树
此解决方案来自svick的解决方案,用于签出旧提交并使其成为新提交:
1 2 3
| git rm -r .
git checkout <commit> .
git commit |
与备选方案1类似,这在当前工作副本中复制了的状态。必须先执行git rm,因为git checkout不会删除之后添加的文件。
- 关于备选方案1,一个简单的问题:这样做,我们就不会在承诺之间松懈,对吗?
- 在备选方案2中,点代表这些命令中的内容?
- @这些点表示一个文件路径,在本例中是当前目录,因此假设您是从工作副本的根目录运行它。
- 这个警告在答案中重复了好几次,但是有人能补充一下为什么这些不是最好的比较方法,比如来自@cascabel(@jefromi's)链接解决方案的git revert HEAD~2..HEAD。我没看到问题。
假设您谈论的是master和相应的分支(也就是说,这可能是您关心的任何工作分支):
1 2 3 4 5
| # Revert local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
# Revert remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master |
我在一篇博文中找到了答案(现在不存在了)
- 这个答案与其他无数答案有什么不同?
- 链接已断开。
- 真不幸。我给博客写手发了邮件-希望他还能收到!
- @peter brokenlink web.archive.org/web/20150411085146/http://lrotherfield.com/b&zwnj;&8203;log/&hellip;
- 对于如何解决这个问题,大多数其他建议都缺少push语法。工作很好。
这里有一个更简单的方法返回到以前的提交(并使其处于未提交状态,您可以随意处理它):
所以,不需要提交ID等等:)
- 不起作用,此操作后的一个git拉将生成:错误:合并将覆盖对以下文件的本地更改:
- @Malhal,这是因为您有未限制的更改。存储/重置它们,然后它将在没有该错误的情况下工作。
在所有更改之后,当您推送所有这些命令时,可能必须使用:
不仅是git push。
- 强制性警告:如果您与其他拥有旧提交副本的人共享您的分支,请不要这样做,因为使用这样的强制推送将强制他们重新同步其工作。有关详细解释如何在不丢失强制推送工作的情况下安全地恢复提交的解决方案,请参阅此答案。
- 有时候这就是你想要的。示例:提交并将多个提交推送到错误的分支(分支A)。在挑选分支B之后,我希望将这些提交从分支A中删除。我不希望进行还原,因为当分支A和B合并在一起时,稍后将应用还原。执行重置——在分支A中执行hard,然后执行force push,将这些提交从分支中删除,同时将它们保存在分支B中。我可以摆脱这种情况,因为我知道分支A上没有其他人在开发。
- 谢谢!我不知道如何让远程分支与本地分支匹配,只需要执行强制推送。
有一个命令(不是核心git的一部分,但它在git extras包中)专门用于恢复和转移旧提交:
在手册页上,还可以这样使用:
1 2
| # Remove the latest three commits
git back 3 |
您可以自己完成所有这些初始步骤,然后返回git repo。
使用git pull --all命令。
使用-n 4从终端运行git log命令。-n后面的数字确定日志中从本地历史记录中最近的提交开始的提交数。
$ git log -n 4
使用git reset --hard HEAD~N重置存储库历史记录的头,其中n是要收回头的提交数。在下面的示例中,头部将被放回一个提交到存储库历史记录中的最后一次提交:
使用git push --force将更改推送到git repo以强制推送变化。
如果您希望Git存储库以前提交
1 2 3
| git pull --all
git reset --hard HEAD~1
git push --force |
还原为最新提交并忽略所有本地更改:
选择所需的提交,并通过检查
1 2 3
| git show HEAD
git show HEAD~1
git show HEAD~2 |
直到你得到所需的承诺。为了说明这一点,一定要
或者是git reset --hard HEAD~2或者其他什么。
- 强制性警告:如果您与其他拥有旧提交副本的人共享您的分支,请不要这样做,因为使用这样的硬重置会迫使他们必须将其工作与新重置的分支重新同步。有关详细解释如何在不丢失硬重置工作的情况下安全地还原提交的解决方案,请参阅此答案。
- 而且,很明显,git show HEAD相当于仅使用git log HEAD -1。
要保留从上一个提交到头的更改并移动到上一个提交,请执行以下操作:
如果上一次提交到头部不需要更改,只需放弃所有更改,请执行以下操作:
这是另一种直接重置为最近提交的方法
1 2
| git stash
git stash clear |
它直接清除自上次提交以来所做的所有更改。
附言:有点问题,它也会删除你最近存储的所有隐藏更改。我想在大多数情况下都不重要。
- 注意:未添加到索引中的新文件不会被存储。您也可以添加或手动删除它们。
- 为什么要清理藏匿处?除了非解决方案,这实际上是有害的。阅读问题的第一句话会立即使存储解决方案失效(只有重新设置为最后一次提交才有用)。
为了彻底清除编码器目录中的某些意外更改,我们使用了:
1 2
| git add -A .
git reset --hard HEAD |
只需git reset --hard HEAD就可以删除修改,但它不能删除"新"文件。在他们的案例中,他们不小心将一个重要文件夹随机拖到了某个地方,所有这些文件都被Git视为新文件,所以一个reset --hard没有修复它。通过预先运行git add -A .,它明确地用git跟踪它们,并通过重置消除它们。
我相信有些人可能会遇到这样的问题,希望知道如何回滚他们在主服务器中所做的承诺更改——即扔掉所有东西,返回到源服务器/主服务器,在这种情况下,执行以下操作:
1
| git reset --hard origin/master |
https://superuser.com/questions/273172/how-to-reset-master-to-origin-master
还原最近的提交:
HEAD只是对当前分支上当前提交(最新)的引用。在任何给定时间只能有一个HEAD。
还原为旧提交:恢复旧版本的最快方法是使用reset命令:
1 2 3 4 5 6 7 8
| # Resets index to former commit
git reset 56e05fced
# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}
# Updates working copy to reflect the new commit
git reset --hard |
这将使您的头分支倒带到指定的版本。在这个版本之后的所有提交都被有效地撤销了;您的项目和那个时候完全一样。
reset命令有两个选项,其中一个更有趣的选项是--soft标志。如果您使用它而不是--hard,那么git将保留这些"未完成"提交中的所有更改作为本地修改。
在新的本地分支中恢复修订
如前所述,在您的HEAD分支上使用reset命令是一个非常激烈的操作:它将删除指定修订之后的任何提交(在此分支上)。如果你确定这是你想要的,一切都很好。
不过,还有一种更安全的方法,以防您更喜欢保持您当前的头分支不变。由于"分支"在Git中既便宜又容易,因此我们可以轻松地创建一个新分支,从旧版本开始:
1
| git checkout -b old-project-state 0ad5a7a6 |
通常,checkout命令只用于切换分支。但是,提供-b参数,还可以让它创建一个新的分支(在本例中称为旧项目状态)。如果您不希望它从当前的头部修订开始,您还需要提供一个提交哈希-我们要恢复的旧项目修订。
现在,您有了一个名为旧项目状态的新分支,它反映了项目的旧版本——不需要触摸甚至删除任何其他提交或分支。
REVERT是回滚提交的命令。
1
| git revert <commit1> <commit2> |
Sample:
git revert 2h3h23233
它可以像下面那样从头部开始移动。这里1说"恢复上次提交"。
git revert HEAD~1..HEAD
然后做git push。
如果情况紧急,而你只想快速而肮脏地完成发问者的要求,假设你的项目在"我的项目"目录下:
复制整个目录并将其命名为其他内容,如"我的项目-复制"
做:
1
| git reset --hard [first-4-letters&numbers-of-commit's-SHA] |
然后系统上有两个版本…您可以检查、复制或修改以前提交的感兴趣的文件或其他文件。如果你已经决定新的工作毫无进展的话,你可以完全放弃"我的项目副本"下的文件。
如果您希望在不实际放弃工作的情况下继续项目的状态,因为这个检索到的提交将再次重命名您的目录:删除包含检索到的提交的项目(或给它一个临时名称),然后将您的"我的项目-复制"目录重命名回"我的项目"。然后很快再做一次承诺。
Git是一个杰出的创造,但你不能仅仅"随时随地"去理解它:同样,那些试图解释它的人往往会假定自己对其他VCS(版本控制系统)有先见之明,并且过早地钻研得太深,并且犯下其他罪行,例如使用可互换的术语"签出",这种方式有时看起来几乎是故意的。混淆初学者。
为了减轻你自己的压力,你必须读一本关于Git的书——我建议你读"带Git的版本控制"。如果我说"必须"的时候你能相信我(或者更确切地说是我的伤疤),那么你现在就可以这么做了。Git的复杂性很大程度上来自于分支和重聚。但从你的问题来看,人们没有理由用科学蒙蔽你的双眼。
特别是,如果,例如,这是一个绝望的情况下,你是一个与吉特新手!
另一种想法是:将git存储库("repo")保存在一个目录中,而不是保存工作文件的目录中,这(现在)实际上非常简单。这意味着您不必使用上述快速和肮脏的解决方案复制整个Git存储库。请参阅fryer使用的答案——这里是单独的git dir。不过,请注意:如果您有一个"单独的目录"存储库,而您没有复制该存储库,并且您进行了硬重置,则重置提交之后的所有版本都将永远丢失,除非您像绝对应该的那样定期备份存储库,最好是将其备份到云端(如Google Drive)以及其他位置。
尝试重置为所需提交-
git reset
(要检查提交ID,请使用git log)
这会将所有更改的文件重置为未添加状态。
现在,您可以通过以下方式删除所有未添加的文件:
git checkout .
检查git log以验证您的更改。
更新
如果在回购中只有一个承诺,请尝试
git update-ref -d HEAD
当您的提交被远程推送时,您需要删除它们。我假设你的分支正在开发中,它被推到了原点上。
您首先需要从源位置移除显影:
1
| git push origin :develop (note the colon) |
然后,您需要获得您想要的开发状态,让我假设提交哈希为efghijk:
1
| git reset --hard EFGHIJK |
最后,再次推动开发:
Caution! This command can cause losing commit history, if user put the wrong commit mistakenly. Always have en extra backup of your git some
where else just in case if you do mistakes, than you are a bit safer.
:)
我也遇到过类似的问题,我想回到以前的承诺。在我的情况下,我没有被灌输保持更新的承诺,因此我使用了Hard。
我就是这样做的:
1
| git reset --hard CommitId && git clean -f |
这将在本地存储库上恢复,在使用git push -f之后,这里将更新远程存储库。
如果您想在最后一次提交中纠正一些错误,一个好的选择是使用git-commit--amend命令。如果最后一次提交没有被任何引用指向,那么这将实现技巧,因为它使用与最后一次提交相同的父级创建提交。如果没有对最后一次提交的引用,它将被丢弃,而这个提交将是最后一次提交。这是一种纠正提交而不恢复提交的好方法。但它也有自己的局限性。
在Gitkraken上,您可以这样做:
右键单击要重置的提交,选择:重置为此提交/硬:
再次右键单击提交,选择:当前分支名称/推送:
点击力推:
obs.:您需要小心,因为硬重置后的所有提交历史记录都将丢失,并且此操作是不可逆的。你必须确定你在做什么。
对于回滚(或还原):
git revert --no-commit"commit-code-to-remove" HEAD
(e.g. git revert --no-commit d57a39d HEAD)
git commit
git push
尝试以上两个步骤,如果你发现这是你想要的,那么git push。
如果发现问题,请执行以下操作:
git revert --abort
首先,获取在某个日期标识提交的字符串,执行以下操作:
1
| git rev-list -n 1 --before="2009-07-27 13:37" origin/master |
它打印提交标识符,获取字符串(例如XXXX)并执行以下操作:
另一个最简单的解决方案是:您必须更改分支才能执行此操作,但之后您只需运行:
1
| git branch -f <<branchname>> 0d1d7fc32e5a947fbd92ee598033d85bfc445a50 |
- 哦,伙计,为什么OP的问题有这么多不同的答案呢?退一步不应该是一个简单的过程吗?
- 谢谢!这种方法适用于裸机回购("git reset"需要工作目录,所以这里的大多数答案对我来说都不起作用)。
使用sourcetree可以更容易地完成。只需右键单击要查找的提交,然后从菜单中选择"签出"。
选择git reflog头的编号,您希望在其中恢复到和执行(对于本例,我选择12):
1
| git reset HEAD@{12} --hard |
由于某种原因,我无法手动还原我的,所以我最终是这样做的。
签出我想要的分支,复制它。
签出了最新的分支。
将我想要的分支的内容复制到最新分支的目录中,覆盖并提交更改。
将分支恢复到任何特定提交的最简单方法是:
签出要恢复的提交或分支。
编辑.git/head并更改要恢复到的分支的引用。
例如:
1
| echo 'ref: refs/heads/example' > .git/HEAD |
如果您随后执行git状态,那么应该看到您所在的分支和希望恢复到的分支之间的所有更改。
如果一切看起来都好,你可以承诺。您还可以使用git diff revert..示例来确保它是相同的。
如果要临时还原更改,因为
您可以使用git日志搜索最后一次工作提交,然后运行
1
| git rebase --onto <commitId> |
当远程分支再次工作时,您可以
对于临时更改,此方法优于Git签出,因为您没有处于分离状态。
重置阶段性更改和提交
git reset命令允许您更改头部—最新的将工作树点提交到存储库中。它修改临时区域或临时区域和工作树。Git能够完全按照您想要的方式处理提交,这意味着您有时需要撤消对Git Add所进行的更改。你可以打电话给git reset HEAD 。有两个选项可以完全消除更改。git checkout HEAD 是一种撤消对临时区域和工作树的更改的快速方法。但是,请小心使用此命令,因为它会删除对工作树的所有更改。Git不知道这些更改,因为它们从未被提交过。运行此命令后,无法恢复这些更改。另一个命令是git reset --hard。它对您的工作树具有同样的破坏性,任何未提交的更改或阶段性更改在运行后都会丢失。运行git reset -hard头与git checkout head执行相同的操作。它不需要文件或路径就可以工作。您可以使用带git reset的--soft。它将存储库重置为您指定的提交,并对所有这些更改进行阶段处理。您已经进行的任何更改都不会受到影响,工作树中的更改也不会受到影响。最后,您可以使用--mixed重置工作树,而不进行任何更改。这也会取消任何已进行的更改。
恢复承诺
有时我们会犯错。不应该共享的提交被推送到公共存储库,提交有一个无法修复的bug,需要撤消,或者您可能不再需要该代码。这些情况都要求使用git revert。git revert命令执行您可能期望的操作。它通过对历史记录应用反向提交来还原单个提交。有时需要还原多个提交以完全撤消更改。您可以使用-no-commit,也可以使用-n通知git执行还原,但在提交更改之前停止。这使您可以将所有恢复提交合并为一个提交,如果需要恢复跨越多个提交的功能,这将非常有用。确保先按与最新提交相反的顺序还原提交。否则,您可能会通过尝试还原尚不存在的代码来混淆Git。
我没看到用樱桃采摘:
樱桃摘A: