通过 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
会使您丢失工作目录中任何未提交的更改)。
补充说明
顺便说一句,也许这并不明显,但在文档中提到<commit>
或<commit-ish>
(或<object>
)的任何地方,您都可以在提交时放置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 其中 如果您的更改已被推送到 公共、共享 远程,并且您想要还原 HEAD
和 <sha-id>
之间的所有提交,那么您可以将提交范围传递给 @987654323 @,
git revert 56e05f..HEAD
它会还原56e05f
和HEAD
之间的所有提交(不包括范围的起点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 --hard
和 git 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 --hard
或git 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 log --graph 显示标签名称和分支名称