通过 Git 中的 SHA 哈希恢复提交? [复制]

Posted

技术标签:

【中文标题】通过 Git 中的 SHA 哈希恢复提交? [复制]【英文标题】:Revert to a commit by a SHA hash in Git? [duplicate] 【发布时间】:2010-12-26 02:06:49 【问题描述】:

我不清楚git revert 的工作原理。例如,我想恢复到一个提交,头部后面有六个提交,恢复中间提交中的所有更改。

说它的SHA 哈希是56e05fced214c44a37759efa2dfc25a65d8ae98d。那我为什么不能这样做:

git revert 56e05fced214c44a37759efa2dfc25a65d8ae98d

【问题讨论】:

尽管这个问题实际上比它现在标记为重复的那个问题更老,但这个问题有更好的答案。 meta.stackexchange.com/questions/147643/… 这个问题和这里的最佳答案可能会让 git 用户感到困惑。只是为了帮助理解术语,您不要恢复到提交。您可以重置为一个提交(就像使用时间机器回到过去)或revert一个提交(就像拉出一个提交,就好像它从未存在过一样- 但是它确实保留了历史记录中的还原信息,允许您在需要时还原还原)另请注意,如果您在此过程中遇到冲突,则不应使用 m 标志并键入提交消息。回顾历史时,git 提供的自动消息会提供更多信息。 这是非常好的反馈。谢谢@alexrogins @alexrogins 拉出一个提交,好像它从未存在过是什么意思?也不确定“revert a revert”指的是什么——尽管欣赏评论,很好的信息,只是在你的观点上寻找更多细节。 @Joe 如果您添加一行代码然后提交该行,如果您要还原它,您将撤消该行代码(无论它在历史上首次写入的位置,都不会必须是最后一次提交)。然后进行还原提交。如果您还原该还原提交,那么您实际上是在撤消撤消(即再次重做原始行) 【参考方案1】:

如果您想在当前 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"

【讨论】:

git reset --hard 56e05fced作为第一个命令,然后跳过最后一个git reset --hard,这不是等效的(并且一个命令更短)吗? 当我这样做时,我最终在工作树中得到了一堆Untracked Files。但是查看历史记录,我可以看到这些文件在“恢复到 SHA”提交中确实有相应的删除提交。因此,在最后git reset --hard 之后,您可以执行git clean -f -d 来清理任何徘徊的未跟踪文件。另外,非常感谢这帮助我解决了危机! 我必须无条件执行git reset --soft HEAD@1 吗?我的意思是总是值为 1? @vemv 是的,除非你想丢弃分支顶端的提交。 git reset 56e05fced 将另一个条目添加到 reflog(运行 git reflog),因此 git reset --soft HEAD@1 只需在调用 git reset 56e05fced 之前将指针移回 HEAD。使用更大的数字(例如git reset --soft HEAD@2)会将新提交附加到 previous 提交上。也就是说,增加数字基本上会丢弃 N-1 提交,其中 N 是您替换 1 的数字。 @Tom HEAD@1 应该被引用为 'HEAD@1' 否则,它对我不起作用(可能每个 zsh 用户)【参考方案2】:

git-revert 所做的是创建一个提交,它撤消在给定提交中所做的更改,创建一个与给定提交相反(嗯,倒数)的提交。因此

git revert <SHA-1>

应该而且确实有效。

如果你想回退到一个指定的提交,你可以这样做,因为这部分历史还没有发布,你需要使用git-reset,而不是 git-revert:

git reset --hard <SHA-1>

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

补充说明

顺便说一句,也许这并不明显,但在文档中提到&lt;commit&gt;&lt;commit-ish&gt;(或&lt;object&gt;)的任何地方,您都可以在提交时放置SHA-1 标识符(完整或缩短)。

【讨论】:

如果您的历史记录在硬重置之前已经被推送到远程,您需要使用@987654330 强制推送新重置的分支@,但是警告这可能会无意中删除其他用户的提交,如果没有删除新的提交,那么它将迫使其他用户重新同步他们的工作与重置分支,所以首先确保您的合作者可以这样做。 这似乎是最好的答案。它还清楚地说明了 git revert 和 git reset 之间的区别。【参考方案3】:

它恢复所述提交,即添加与其相反的提交。如果您想签出较早的版本,请执行以下操作:

git checkout 56e05fced214c44a37759efa2dfc25a65d8ae98d

【讨论】:

那我可以把它和头部合并吗?如果我预计会有大量冲突怎么办,我可以强制此提交“按原样”作为头部并覆盖任何冲突吗? 我不确定你在说什么头。你可以移动你的头回到这个提交。 (例如通过删除和创建分支)。如果您想在头部进行“合并”提交,这实际上是中间提交的反转,您可以使用合并“我们的”策略。选择您的选项并阅读手册页。力量正等着你去使用它;-) 有道理,我问的原因是 git 现在告诉我我不在任何分支上。 因为你不是。如果您输入git branch,您将清楚地看到它。例如,您可以通过git checkout -b mybranch 56e05 使用分支来获取它。 我想他是在问如何进行快进【参考方案4】:

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

git reset --hard <commit-id>

然后:

git push <reponame> -f

【讨论】:

新手应该知道push -f可以破坏历史。但是,有时这正是您想要的 :) 有时你真的很高兴历史记录被删除...正在寻找这个 -f 选项,谢谢! 谢谢,字面意思,我必须输入 -> git push origin master -f 其中 至少对我来说不能只是来源 正如人们上面提到的,如果我们希望我们的 repo 头指向特定的提交而不维护历史记录,那么使用上述步骤,否则我们可以使用 git revert。 我们是否知道谁已经重置(即回滚提交)并强制推送到特定分支?【参考方案5】:

如果您的更改已被推送到 公共、共享 远程,并且您想要还原 HEAD&lt;sha-id&gt; 之间的所有提交,那么您可以将提交范围传递给 @987654323 @,

git revert 56e05f..HEAD

它会还原56e05fHEAD 之间的所有提交(不包括范围的起点56e05f)。

【讨论】:

请注意,如果您要还原数百个提交,这可能需要一段时间,因为您必须单独提交每个还原。 @splicer 您不必单独还原每个提交,您可以传递 --no-edit 选项以避免生成单独的提交消息,或者您可以使用 --no-commit 提交还原一下子。 @Cupcake 你是对的 HEAD..56e05f 对我不起作用,但 56e05f..HEAD 成功了 这是迄今为止我首选的回滚方式,无论您是否推动它。我将此添加到我的全局 ~/.gitconfig 下的别名部分:rollback = "!git revert --no-commit $1..HEAD #" - 所以现在我可以直观地做到 $ git rollback a1s2d3 这似乎与我想要的非常接近,但我有大约 30 个提交要还原,但在与 error: Commit 6b3d9b3e05a9cd9fc1dbbebdd170bf083de02519 is a merge but no -m option was given. fatal: revert failed 的合并提交中大约一半失败 - 有什么建议吗?我尝试添加 -m 但不太确定如何使用它【参考方案6】:

更新:

如果两者之间没有合并提交,则此答案提供了一种更简单的方法:https://***.com/a/21718540/541862

但是,如果有一个或多个合并提交,则该答案将不起作用,因此请坚持此答案(适用于所有情况)。

原答案:

# 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

git reset --hardgit reset --soft 这两个命令在这里很神奇。第一个更改了工作目录,但它也更改了 head (当前分支)。我们用第二个来修复头部。

【讨论】:

提交中的 -a 不是必需的。 完美。这应该成为 git cli 中的一个命令,IMO。 非常好!这比git revert 56e05fce..HEAD 好得多,因为它只是一次提交 嗯,我收回了,这更简单:***.com/questions/4114095/… @knocte 实际上不,您提供的链接并不简单,即使它有成千上万的赞成票。原因是如果范围内有一个或多个合并提交,它根本就不起作用,这种情况经常发生。这个确实应该是最佳答案。【参考方案7】:

这样比较好理解:

git checkout 56e05fced -- .
git add .
git commit -m 'Revert to 56e05fced'

并证明它有效:

git diff 56e05fced

【讨论】:

恐怕这通常是不正确的。结帐只会(我认为)更新存在的路径,因此如果自56e05fced 以来已删除文件,则不会通过执行git checkout 56e05fced -- . 来暂存它 此解决方案不会删除自 56e05fced 以来添加的新文件,就像git reset --hardgit revert 一样。 如果你真的想恢复56e05fced的状态,你真的想使用这些命令,而不是git checkout 注意:这将使您处于分离的头部状态。不建议! 这对我有用,但在这种情况下“--”是什么意思?【参考方案8】:

应该很简单:

git reset --hard 56e05f

这会让你回到那个特定的时间点。

【讨论】:

...而且非常危险,因为包括其他人的工作会抹去所有的历史。 小心这个!【参考方案9】:

这可能有效:

git checkout 56e05f
echo ref: refs/heads/master > .git/HEAD
git commit

【讨论】:

这基本上和git reset --hard 56e05f 做同样的事情,除了这更不安全而且更hacky。您不妨使用Charle's solution 或Jakub's solution。

以上是关于通过 Git 中的 SHA 哈希恢复提交? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在 Git 中的根提交之前添加提交? [复制]

Git中添加但未提交的已删除文件可以恢复吗? [复制]

如何使用 git log --graph 显示标签名称和分支名称

如何使用git(git config --global)?

从 Git 中恢复无法读取 blob,文件现在有不同的哈希?

git 如何计算文件哈希?