如何将 git 代码库回滚至特定的提交?

541

我的代码库当前有100个提交。我需要将代码库回滚到第80个提交,并删除所有随后的提交。

为什么要这样做?

这个代码库是用来合并来自各种用户的代码的。由于编辑过度,一堆合并被作为我的提交提交了进去。这是由于我的远程分支错标导致的,其中3个开发者被错误地标记为彼此。我需要重置到该点,然后再向前拉取。

我想像这个例子中那样进行变基:如何在GitHub上删除提交?

然而,Git要求我做很多冲突管理,有更简单的方法吗?

7个回答

1110
git reset --hard <old-commit-id>
git push -f <remote-name> <branch-name>

注意:正如下面的评论所写,在协作环境中使用这个是很危险的:你正在重写历史


63
大家,执行 git push -f origin branch。我之前犯了这个错误,导致遇到了麻烦。请务必注意。 - Sumit M Asok
29
小心!这会导致你在本地丢失所有提交记录,如果你进行推送就再也无法找回。请注意! - Thomas
10
不是这样的,你可以使用git reflog获取旧的提交记录。 - Jan Schaefer
34
你可能需要执行git push origin HEAD --force而不是git push -f origin branch,因为后者会给我一个error: src refspec branch does not match any.的错误提示。 - sprocket12
1
是的,谢谢大家。我成功地完成了我想做的事情。我首先从我想要回滚的提交前面创建了一个单独的分支。将其本地克隆。然后在该副本上应用了您的建议,这样,我就没有损害我的主分支... - Gauthier Boaglio
显示剩余5条评论

45

要撤销最近的提交,我需要执行以下操作:

首先:

git log

获取最新的SHA ID以进行撤销。

git revert SHA

这将创建一个新的提交,它会完成与您的提交完全相反的操作。然后,您可以推送此新提交以将应用程序恢复到之前的状态,您的git历史记录将相应地显示这些更改。

对于我发现的情况更多的是,这对于立即重做刚刚提交的内容非常有用。

正如Mike提到的,您也可以这样做:

git revert HEAD

11
git revert HEAD 可以撤销最近一次的提交,而无需查找哈希值。 - Mike Baranczak
这是一个解决方案,如果您根本不想删除提交。然而,在这种情况下,所有垃圾提交仍将存在,并允许克隆者重置或检出到它们。如果您想防止这种情况发生,您必须强制推送。 - cst1992
1
注意:这些还原操作可以堆叠,这意味着如果您不小心还原了,您可以使用另一个还原操作来还原该还原操作。 - Ginger
被接受的答案很棒,但我认为这个答案需要更多人看到,因为RESET和REVERT之间存在差异,如果人们在协作环境中工作,这可能非常重要。以下是一个很好的解释: https://dev59.com/JWsy5IYBdhLWcg3wvgdk - jcodes

20

另一种方法:

检出要还原的分支,然后将本地工作副本重置回您想要成为远程服务器上最新版本的提交(它之后的所有内容都将消失)。在SourceTree中,我右键单击并选择“将BRANCHNAME重置为此提交”来执行此操作。

然后导航到存储库的本地目录,并运行此命令:

git -c diff.mnemonicprefix=false -c core.quotepath=false push -v -f -- tags REPOSITORY_NAME BRANCHNAME:BRANCHNAME 

这将在您的本地代码库中,从当前分支开始擦除所有提交记录,但仅针对该分支。


1
请注意,“REPOSITORY_NAME”将类似于https:/me@github.com/me/repo_name.git - tim
4
如果您能将那个命令分解并加以说明,将会更有帮助。请注意不改变原意,使内容通俗易懂。 - cst1992

10

大多数建议都假定你需要某种方式销毁最后的20个提交,这就是所谓的“重写历史”的原因,但你并不需要这样做。

只需从提交号为80的提交上创建一个新分支,并在该分支上进行后续工作。另外的20个提交将保留在旧的分支中。

如果你绝对想让你的新分支具有相同的名称,请记住分支基本上只是标签。将你的旧分支重命名为其他名称,然后以你想要的名称在提交号为80的提交上创建新的分支即可。


我猜这也会给每个人感兴趣的分支的本地版本的历史记录带来问题。 - interestedparty333
如果需要这样大的回滚,那么肯定每个人的本地版本都需要再次拉取最新的(由第一个人准备)。如果您想要“回滚回滚”,这样做会更安全。 - F. Kam

5

当我从主分支更新分支时,有时候会误操作导致将分支合并到主分支中。发现了一种撤销的方法。

如果你的最后一次提交是一个合并操作,需要做更多的处理:

git revert -m 1 HEAD


当我在远程代码库上撤销提交时,它对我很有效。 - Dr. Mian

3

在 GitHub 上,最简单的方法是在分支选项卡下使用 GitHub UI 删除远程分支。您必须确保删除以下设置才能使分支可删除:

  1. 不是默认分支
  2. 没有打开的拉取请求
  3. 该分支未受保护

现在,在本地存储库中重新创建它,以指向以前的提交点,并将其添加回远程存储库。

git checkout -b master 734c2b9b   # replace with your commit point

然后将本地分支推送到远程。
git push -u origin master

添加默认分支和分支保护等。

1
git log

切换分支:(注1)

git checkout branch_name

本地备用方案:

git reset --soft commitID  

这个命令只会在指定的commitID之后删除提交日志,同时保留对代码所做的更改。
git reset --hard commitID  

这个命令会彻底移除在指定的commitID之后所做的更改,有效地使代码回滚到之前的状态。
同步远程仓库:(注意2)
git push origin HEAD --force

*(注意 1) Git 在切换分支前会提示你提交或隐藏修改过的代码。如果你在未提交修改的情况下尝试切换到另一个分支,将会出现以下提示:“请提交您的更改或在切换分支之前存储它们”。但是,如果你尚未完成当前分支的开发工作,那么提交可能会感觉不完整。在这种情况下,你可以使用 “git stash” 命令隐藏已修改但未提交的代码。这将还原代码到上一次提交的状态,并不显示修改后的代码。当你返回到正在工作的分支时,可以使用 “git stash pop” 命令恢复隐藏的代码。

(注意 2) 如果你遇到错误消息“fatal: unable to access 'https://github.com/xxxxx/xxxxxxx.git/': OpenSSL SSL_read: Connection was reset, errno 10054”,原因可能是服务器的 SSL 证书没有由第三方签名。要解决此问题,你可以在 Git Bash 中输入 git config --global http.sslVerify "false" 以禁用 SSL 验证,然后再尝试操作。*


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接