【问题标题】:How can I undo pushed commits using git?Git - 撤消推送的提交
【发布时间】:2014-05-06 03:30:45
【问题描述】:

我在远程存储库中有一个项目,与本地存储库(开发)和服务器(生产)同步。我一直在进行一些已提交的更改,这些更改已经推送到远程并从服务器中拉出。现在,我想撤消这些更改。所以我可以在更改之前git checkout 提交新更改并提交新更改,但我猜测将它们再次推送到远程会有问题。关于我应该如何进行的任何建议?

【问题讨论】:

    标签: git


    【解决方案1】:

    您可以通过以下方式恢复单个提交:

    git revert <commit_hash>
    

    这将创建一个新的提交,它会还原您指定的提交的更改。请注意,它只恢复该特定提交,而不是之后的提交。如果你想恢复一系列提交,你可以这样做:

    git revert <oldest_commit_hash>..<latest_commit_hash>
    

    它会还原 &lt;oldest_commit_hash&gt; 之后的所有提交,包括 &lt;latest_commit_hash&gt;。在某些版本的 git 上,它还会还原 &lt;oldest_commit_hash&gt;,因此请仔细检查该提交是否被还原。您始终可以使用g reset --hard HEAD~ 删除最新的还原提交(还原最旧的提交)。

    要知道提交的哈希值,您可以使用git log

    查看git-revert man page 以获取有关git revert 命令的更多信息。另外,请查看 this answer 了解有关恢复提交的更多信息。

    【讨论】:

    • 换句话说,它恢复到 ;)
    • 在 git 文档中,它说 revert 命令在第一次和最后一次提交之间恢复提交(包括第一次和最后一次)。 See Documentation
    • @aod 是正确的,这个答案需要更新。当前用于还原的 git API 已将 &lt;oldest_commit_hash&gt; 包含在还原列表中
    • with git 2.17.2 revert .. 不包括旧但包括
    • 刚刚试过....最后一步错过了,在 "git revert " 使用 "git push origin " 之后
    【解决方案2】:

    一个不保留“撤消”痕迹的解决方案。

    注意:如果有人已经提取了您的零钱,请不要这样做 (我只会在我的个人仓库中使用它。)

    运行:

    git reset <previous label or sha1>
    

    这将在本地重新签出所有更新(因此 git status 将列出所有更新的文件)

    然后你“做你的工作”并重新提交你的更改(注意:此步骤是可选的)

    git commit -am "blabla"
    

    此时您的本地树与远程树不同

    git push -f <remote-name> <branch-name>
    

    将强制远程分支接受此推送并删除前一个(指定远程名称和分支名称不是强制性的,但建议避免使用更新标志更新所有分支)。

    !!注意一些标签可能仍然指向删除提交! how-to-delete-a-remote-tag

    【讨论】:

    • -a 所有被跟踪的文件都将被提交 -m 提交消息跟随
    • 正是我搜索的内容。有人做了一个错误的提交,然后推送并再次恢复它。因此无法合并分支,我想让存储库再次处于正确状态(并从历史记录中删除提交,因为它们无论如何都是错误的)
    • 我应该使用哪个“previous label or sha1”?我应该输入最后一个“正确”的还是之前的那个,然后重新做最后一个正确的所做的所有更改?
    • 错误提交之前的那个
    • 正是我需要的。我错误地将一个分支推到了master上。结果,我在所有提交历史中都有很多垃圾提交。我刚刚完成了git push -f 的最后一次正确提交和远程历史清理!谢谢!
    【解决方案3】:
    git revert HEAD -m 1
    

    在上面的代码行中。 "最后一个参数代表"

    • 1 - 恢复一个提交。

    • 2 - 恢复最后两次提交。

    • n - 恢复上一个 n 提交。

    你需要在这个命令之后 push 才能远程生效。您还有其他选项,例如指定要还原的提交范围。这是选项之一。


    以后用git commit -am "COMMIT_MESSAGE" 然后git pushgit push -f

    【讨论】:

    • 这不是真的 - -m 参数指定要恢复到的父级的数量(如果您想恢复传入的“他们的”更改,通常为 1,而合并到更改则为 2 , "ours" - 用于合并 2 个提交)。它与还原的提交数量无关 - 如果要还原提交范围,请使用 git revert ref1..ref2
    • 没有达到预期的效果
    【解决方案4】:

    在这些情况下我要做的是:

    • 在服务器中,将光标移回上次已知的良好提交:

      git push -f origin <last_known_good_commit>:<branch_name>
      
    • 在本地,做同样的事情:

      git reset --hard <last_known_good_commit>
      #         ^^^^^^
      #         optional
      



    查看我为此目的创建的分支 my_new_branch 的完整示例:

    $ git branch
    my_new_branch
    

    这是在myfile.py添加一些东西后的最近历史:

    $ git log
    commit 80143bcaaca77963a47c211a9cbe664d5448d546
    Author: me
    Date:   Wed Mar 23 12:48:03 2016 +0100
    
        Adding new stuff in myfile.py
    
    commit b4zad078237fa48746a4feb6517fa409f6bf238e
    Author: me
    Date:   Tue Mar 18 12:46:59 2016 +0100
    
        Initial commit
    

    我想摆脱已经推送的最后一次提交,所以我运行:

    $ git push -f origin b4zad078237fa48746a4feb6517fa409f6bf238e:my_new_branch
    Total 0 (delta 0), reused 0 (delta 0)
    To git@github.com:me/myrepo.git
     + 80143bc...b4zad07 b4zad078237fa48746a4feb6517fa409f6bf238e -> my_new_branch (forced update)
    

    不错!现在,我看到在该提交 (myfile.py) 中更改的文件显示在“未暂存提交”中:

    $ git status
    On branch my_new_branch
    Your branch is up-to-date with 'origin/my_new_branch'.
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
        modified:   myfile.py
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    由于我不想要这些更改,我也只是将光标移回本地:

    $ git reset --hard b4zad078237fa48746a4feb6517fa409f6bf238e
    HEAD is now at b4zad07 Initial commit
    

    所以现在 HEAD 在本地和远程的上一次提交中:

    $ git log
    commit b4zad078237fa48746a4feb6517fa409f6bf238e
    Author: me
    Date:   Tue Mar 18 12:46:59 2016 +0100
    
        Initial commit
    

    【讨论】:

    • 这是正确答案!这正是我需要做的,谢谢今天学到了一些新东西:)
    • 这是正确答案!这是关于 push(!) 提交!
    • 如果您想真正还原更改(就好像您从未推送过它们一样),这正确答案。
    • 完美答案。效果符合预期!
    • 完美答案。
    【解决方案5】:

    如果您通过 git 命令行按照下面给出的步骤操作,您可以恢复(或者您也可以将其称为 DELETE)Git 提交 本地和远程

    运行以下命令以查看要还原的提交 ID

    git log --oneline --decorate --graph
    

    你会得到如下截图

    如果您还检查了远程 (通过 Web 界面),那么您可以看到这将如下所示

    根据屏幕截图,您目前处于提交 ID e110322,但是您想恢复到 030bbf6 BOTH LOCALLY 和 REMOTELY

    执行以下步骤来删除/恢复本地+远程提交


    首先本地恢复到提交 id 030bbf6

    git reset --hard 030bbf6
    

    紧随其后

    git clean -f -d
    

    这两个命令清除强制重置到提交阶段030bbf6,如下图所示

    现在如果你跑 git status 然后你会看到你是来自远程分支的两个提交,如下所示

    运行以下以更新您的索引(如果有任何更新)。建议您要求所有开发人员不要在主远程分支上接受任何拉取请求。

    git fetch --all
    

    完成后,您需要在分支前使用 + 符号Push 强制,如图所示以下。我这里用的是 master 分支,你可以用任何替换它

    代码

    git push -u origin +master
    

    现在,如果您看到远程的 web 界面,那么提交也应该被还原。

    【讨论】:

    • 这是最好的答案,因为它实际上是用一个例子来解释的!感谢那。但是,我收到以下错误:! [远程拒绝] master -> master (pre-receive hook denied) 错误:尽管拥有维护者身份等,但未能将一些参考推送到 'gitlab.com:information-provision/collectors/deribit-collector.git'
    • @user6400946 您是否使用“+”(加号)符号,如上一条命令所示? git push -u origin +YourBrandName
    • 是的,不过我刚刚解决了。看来我的主分支受到强制推送的保护,我需要暂时取消保护它(在 gitlab 存储库设置下)。
    【解决方案6】:

    这将删除您推送的提交

    git reset --hard 'xxxxx'
    
    git clean -f -d
    
    git push -f
    

    【讨论】:

    • 此方法正确重写历史以删除提交。太棒了
    • 这个答案是 el magnifeco!
    • 明确一点(我不确定):提交将是操作后的当前提交。不是最后一个要删除的。
    • 警告:我不小心恢复为 PARENT(而不是 COMMIT),请注意 :)
    • clean 很危险。它会删除不受版本控制的文件!
    【解决方案7】:

    这是我的方式:

    假设分支名称是develop

    # Checkout a new temp branch based on one history commit
    git checkout <last_known_good_commit_hash>
    
    # Delete the original develop branch 
    git branch -D develop
    # Create a new develop branch based on the temp branch
    git checkout -b develop
    
    # Force update this new branch
    git push -f origin develop
    
    

    【讨论】:

    • 我可以确认它有效!节省时间,就这样吧。
    • 对我来说,从这个答案中可以学到很多东西,所以我选择了这个。
    【解决方案8】:

    你可以这样做

    git push origin +<short_commit_sha>^:<branch_name>
    

    【讨论】:

    • 能否详细说明命令中的 +、^ 和 : 字符?
    【解决方案9】:

    2020 简单方法:

    git reset <commit_hash>
    

    (您要保留的最后一次提交的哈希)。

    您将在本地保留现在未提交的更改。

    如果你想再次推送,你必须这样做:

    git push -f
    

    【讨论】:

    • 它并不总是有效,因为管理员可以阻止重写历史,这在行业中很常见。因此@gitaarik 提到的解决方案将起作用。 git revert git push origin
    • 这很短,很简单,它完全符合我的需要。谢谢!
    【解决方案10】:

    重置对我来说很辛苦: 谢谢@Mo D Genensis 和@vibs2006

    
    git reset --hard 'your last working commit hash'
    
    git clean -f -d
    
    git push -f
    

    【讨论】:

    • 这会覆盖已更改的文件并删除已添加的文件。
    【解决方案11】:

    另一种无需还原(撤消痕迹)的方式:

    如果其他人推送了其他提交,请不要​​这样做

    创建分支的备份,位于您的分支my-branch 中。因此,如果出现问题,您可以重新启动该过程而不会丢失任何已完成的工作。

    git checkout -b my-branch-temp
    

    回到你的分支。

    git checkout my-branch
    

    重置,放弃你的最后一次提交(撤消它):

    git reset --hard HEAD^
    

    删除远程分支(例如origin 远程)。

    git push origin :my-branch
    

    将您的分支(没有不需要的提交)重新推送到远程。

    git push origin my-branch
    

    完成!

    希望对您有所帮助! ;)

    【讨论】:

      【解决方案12】:

      假设61234 是您要保留的最后一个良好提交的 sha-number。

      git reset --hard 61234
      git push -f
      

      将完全删除所有错误的提交而不留任何痕迹。

      注意:如果您想将(您重置的提交)推送到特定分支,您可以使用 git push -f origin branch-name

      【讨论】:

      • 谢谢!并且提交历史是无辜的!为了方便获取我使用的 sha-number: $ git log --oneline .
      • 这应该是公认的答案!
      • 运行git push -f origin master 时出现remote: GitLab: You are not allowed to force push code to a protected branch on this project. 错误。我想我必须在我的 gitlab 服务器上更改一些配置。
      • 我编辑了你的答案,因为当我真的想重置分支上的提交时,我差点跑了git push -f origin master——很高兴它没有成功!
      【解决方案13】:

      干净利落:

      git rebase -i <hash of last good commit, 9 chars is enough>
      

      现在您将获得从最后一次良好提交到HEAD 的提交列表,其中包含如何处理每个提交的选项。 DROP 将丢弃该提交。保存文件。

      现在修复上游做:

      git push --force-with-lease
      

      With lease 这样您就不会意外地给处理您推送更新的其他人带来问题)

      这通过删除错误的提交而不是引入新的提交来修复早期的错误提交来保持日志清洁。

      【讨论】:

      • 这不起作用,因为它会创建一个分歧的分支并且您无法推送它(即使使用 -force 也不行)。但如果它正在工作,那将是最好的解决方案......
      • @rimes,我在用于生产的代码上使用过这种类型的构造,可能不是经常使用,但多次使用。一位同事(我们的常驻 git 大师)使用它来压缩来自 PR 的代码,其中包含大量提交以合并提交并保持主分支日志干净。
      猜你喜欢
      • 2022-05-31
      • 1970-01-01
      • 1970-01-01
      • 2011-09-20
      • 1970-01-01
      • 2020-06-30
      • 1970-01-01
      • 2020-06-12
      • 2012-07-18
      相关资源
      最近更新 更多