在Git中恢复由SHA哈希提交?

JP *_*shy 574 git

我不清楚如何git revert工作.例如,我想在头部后面恢复提交六次提交,恢复中间提交之间的所有更改.

说它的SHA哈希是56e05fced214c44a37759efa2dfc25a65d8ae98d.那我为什么不能做以下事情:

git revert 56e05fced214c44a37759efa2dfc25a65d8ae98d
Run Code Online (Sandbox Code Playgroud)

CB *_*ley 1103

如果要在当前HEAD上提交具有不同提交的确切状态,撤消所有中间提交,则可以使用reset创建索引的正确状态来进行提交.

# Reset the index and working tree to the desired tree
# Ensure you have no uncommitted changes that you want to keep
git reset --hard 56e05fced

# Move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert to 56e05fced"
Run Code Online (Sandbox Code Playgroud)

  • 它不是等同的(并且命令更短):`git reset --hard 56e05fced`作为第一个命令,然后跳过最后的`git reset --hard`? (85认同)
  • 当我这样做时,我在工作树中得到了一堆"Untracked Files".但是看一下历史记录,我可以看到那些文件在"Revert to SHA"提交中确实有相应的删除提交.所以在最后的`git reset --hard`之后,你可以做`git clean -f -d`来清理任何徘徊的未跟踪文件.另外,非常感谢,这帮助我解决了危机! (25认同)
  • @vemv是的,除非你想丢弃分支顶端的提交.`git reset 56e05fced`在reflog中添加了另一个条目(运行`git reflog`),所以`git reset --soft HEAD @ {1}`只需在调用`git reset 56e05fced之前将指针移回`HEAD`. .使用更高的数字(例如`git reset --soft HEAD @ {2}`)会在*previous*commit上附加新的提交.也就是说,增加数量将基本上抛弃`N-1`提交,其中`N`是你替换`1`的数字. (6认同)
  • 我必须无条件地执行`git reset --soft HEAD @ {1}`吗?我的意思是总是值为1? (5认同)
  • @Tom**这个解决方案有效**.你一定做错了,或者你的reflog中可能没有任何条目(例如,如果它是一个非常新的克隆).无论如何,您将在[此答案](http://stackoverflow.com/a/4114122/456814)中找到更多直观的"恢复"分支的解决方案. (2认同)
  • @Tom`HEAD @ {1}`应该引用为'HEAD {@ 1}'`否则,它对我不起作用(可能是每个zsh用户) (2认同)

Jak*_*ski 132

什么混帐复归确实是一个指定的提交创建一个承诺,撤消在给定提交所做的更改,创建提交其反向(当然,倒数).因此

git revert <SHA-1>
Run Code Online (Sandbox Code Playgroud)

应该而且确实有效.

如果你想回退到指定的提交,并且你可以这样做,因为这段历史尚未发布,你需要使用git-reset,而不是git-revert:

git reset --hard <SHA-1>
Run Code Online (Sandbox Code Playgroud)

(注意,--hard这将使您丢失工作目录中的任何未提交的更改).

补充说明

顺便说一句,也许它并不明显,但在文档说<commit><commit-ish>(或<object>)的任何地方,你都可以提交一个SHA-1标识符(完整或缩短).

  • **如果您在执行硬重置**之前已将历史记录推送到远程,则需要使用`git push -f`强制推送新重置的分支,但**被警告**这可能会无意中删除其他用户的提交,如果不删除新的提交,则会强制其他用户使用重置分支重新同步他们的工作,**因此请确保首先与您的协作者一起使用.** (4认同)
  • 这似乎是最好的答案。它还清楚地说明了 git revert 和 git reset 之间的区别。 (2认同)

Mic*_*ker 87

它恢复了所述提交,即添加与其相反的提交.如果要签出早期版本,请执行以下操作:

git checkout 56e05fced214c44a37759efa2dfc25a65d8ae98d
Run Code Online (Sandbox Code Playgroud)

  • 因为你不是.如果你键入`git branch`,你会清楚地看到它.例如,您可以使用`git checkout -b mybranch 56e05`来获取分支. (9认同)

小智 64

回滚到特定提交的最佳方法是:

git reset --hard <commit-id>
Run Code Online (Sandbox Code Playgroud)

然后:

git push <reponame> -f
Run Code Online (Sandbox Code Playgroud)

  • 新手应该知道`push -f`可以破坏历史.但是,有时候这就是你想要的:) (27认同)

Flu*_*dan 58

如果您的更改已经被推到一个公共的,共享的远程,并要恢复之间的所有提交HEAD<sha-id>,那么你可以通过一个承诺范围内git revert,

git revert 56e05f..HEAD
Run Code Online (Sandbox Code Playgroud)

它将恢复56e05f和之间的所有提交HEAD(不包括范围的起点56e05f).

  • @splicer你不必单独恢复每个提交,你可以传递`--no-edit`选项以避免必须提交单独的提交消息,或者你可以使用`--no-commit`来提交转换一次全部. (6认同)
  • @thelem`git revert HEAD..56e05f`**完全是使用**的*wrong*命令,`git revert 56e05f..HEAD`已经以相反的顺序恢复提​​交以避免冲突. (5认同)
  • 请注意,如果您要恢复数百个提交,这可能需要一段时间,因为您必须单独提交每个恢复。 (2认同)
  • 这是迄今为止我首选的回滚方式,无论你是否按下它.我把它添加到别名部分下的全局`〜/ .gitconfig`:`rollback ="!git revert --no-commit $ 1..HEAD#"` - 所以现在我可以直观地做`$ git rollback a1s2d3` (2认同)
  • 这看起来非常接近我想要的,但我有大约 30 个提交要恢复,但大约一半的时间在合并提交上失败,并显示“错误:Commit 6b3d9b3e05a9cd9fc1dbbebdd170bf083de02519 是一个合并,但没有给出 -m 选项。致命:恢复失败` - 有什么建议吗?我尝试添加 -m 但不太确定这将如何与此一起使用 (2认同)

Jac*_*Dam 21

更新:

这个答案比我的回答简单:如何将Git存储库恢复到之前的提交?

原始答案

# Create a backup of master branch
git branch backup_master

# Point master to '56e05fce' and
# make working directory the same with '56e05fce'
git reset --hard 56e05fce

# Point master back to 'backup_master' and
# leave working directory the same with '56e05fce'.
git reset --soft backup_master

# Now working directory is the same '56e05fce' and
# master points to the original revision. Then we create a commit.
git commit -a -m "Revert to 56e05fce"

# Delete unused branch
git branch -d backup_master
Run Code Online (Sandbox Code Playgroud)

这两个指令git reset --hardgit reset --soft亦幻这里.第一个更改工作目录,但它也改变了头.我们通过第二个修复头部.

  • @knocte 实际上不,您提供的链接并不简单,尽管它有数千个赞成票。原因是,如果范围内有一个或多个合并提交(这种情况经常发生),它根本不起作用。这确实应该是最重要的答案。 (5认同)
  • 您的提交中的 -a 不是必需的。 (3认同)
  • 完善.这应该成为国际海事组织git cli中的一个单一命令. (3认同)
  • 非常好!这比`git revert 56e05fce..HEAD`要好得多,因为它只是一次提交 (2认同)
  • 嗯,我把它拿回来,这更简单:http://stackoverflow.com/questions/4114095/revert-to-a-previous-git-commit#answer-21718540 (2认同)

小智 6

这样就更容易理解了:

git checkout 56e05fced -- .
git add .
git commit -m 'Revert to 56e05fced'
Run Code Online (Sandbox Code Playgroud)

并证明它有效:

git diff 56e05fced
Run Code Online (Sandbox Code Playgroud)

  • 恐怕这总体上是不正确的。签出只会(我认为)更新存在的路径,因此如果自“56e05fced”以来已删除文件,则不会通过执行“git checkout 56e05fced --”来暂存该文件。 (6认同)