替换git中的提交

时间:2012-11-09 22:33:16

标签: git github

我很久以前就提交了一个糟糕的提交,我想将它完全从git历史中删除,好像它从未发生过一样。我知道提交ID让我们说1f020。我已经尝试了git rebase并将其删除,但是在重新定位时存在很多冲突,这是不可能的。该提交是一个简单的1行代码更改,并推送一些与项目无关的文件。 所以我想写一行代码更改并提交它,然后替换以某种方式用很久以前的那个替换这个新的提交。

4 个答案:

答案 0 :(得分:6)

如果违规提交在私有存储库中,那么您想要做的事情并不是什么大问题。重写已发布的git历史记录会让您的协作者感到恼火,因此请确保删除此行是值得的。

git-rebase documentation有一段有用的段落。

git rebase [...] [<--onto newbase>] [<upstream>] [<branch>]
     

也可以使用rebase删除一系列提交。如果我们有以下情况:

E---F---G---H---I---J  topicA
     

然后命令

git rebase --onto topicA~5 topicA~3 topicA
     

将导致删除提交 F G

E---H'---I'---J'  topicA
     

如果 F G 以某种方式存在缺陷,或者不应该成为topicA的一部分,则此功能非常有用。请注意,--onto上游参数的参数可以是任何有效的commit-ish。

假设您的历史记录是线性的并且违规提交位于您的主分支中,您可以通过运行

来调整上述示例
git rebase --onto 1f020~ 1f020 master

对于更多的情况,请使用交互式rebase。您可能会发现按下an example that merges two commits会很有帮助,但不要使用s标记提交,而是删除整行以从历史记录中删除提交。

答案 1 :(得分:5)

这有点复杂,但无论如何,这是如何进行的:

分离头并移动以提交 AFTER 该错误提交。使用git log查找1f020之后的下一次提交。

git checkout <SHA1-for-commit-just-after-bad-commit-1f020>

移动HEAD只提交 BEFORE 提交错误,但保留索引和工作树

git reset --soft <SHA1-for-just-previous-to-bad-commit-1f020>

重做提交只是 AFTER 错误提交重新使用提交消息,但现在提交只是 BEFORE 那个错误的提交。因此,删除那个错误的提交

git commit -C <SHA1-for-commit-just-after-bad-commit-1f020>

重新应用提交中的所有内容,只需将 AFTER 提交到此新地点

git rebase --onto HEAD <SHA1-for-commit-just-after-bad-commit-1f020> master

答案 2 :(得分:1)

你永远不应该从git的历史中删除提交。你以后会遇到问题。

但是如果你知道自己在做什么,你可以在本地回溯你的历史记录,用当前的提交替换那个提交,然后再次重播所有提交 - 然后对你的存储库进行强制推送。

但我强烈建议不要这样做。只是做一个新的提交,并认为历史上有一个错误的提交。

答案 3 :(得分:1)

所以,你想要的是:

  1. 从历史记录中删除错误提交,

  2. 不必重做已删除提交后出现的所有合并。即从已删除的提交中下降的每个提交都应保持原样,只需最低限度地更改为不包括从历史记录中删除的更改。

  3. 基于git rebase --ontogit rebase -i的解决方案在第二点失败,因为它们需要重做以后发生的所有合并。但是,理论上可以简单地重新创建所有这些其他提交,就好像违规提交从未发生过一样,前提是错误提交足够小,从而将其从后继者本身恢复会产生冲突。

    正如迈克尔和其他人所指出的那样,这样做是非常不可取的。这也是一项重大任务,几乎肯定不值得付出努力。但是,对于教育价值,这里是一个实现目标的综合解决方案的概述:

    • 备份存储库。

    • 使用git rev-list生成一个以错误提交开头的提交列表,并指向可以从中提交提交的所有分支头。

    • 初始化一个空地图,将旧提交映射到新提交。

    • 对于列表中的每个提交,请执行以下操作:

      • 检查提交并从错误提交中恢复更改
      • 使用git write-tree
      • 从当前树中创建一个树对象
      • 使用git commit-tree创建一个新提交,其中包含新树,旧提交消息以及使用上述地图从旧父母翻译的父母(如果某些父母不在地图中,只需使用旧父母)< / LI>
      • 在提交映射中注册新提交。
    • 浏览标记和标记对象,并重新创建它们以指向新提交,并查看地图。

    • 通过分支机构并致电git update-ref,将他们指向新的提交,咨询地图。

    如果提交引入的单行更改(以及不必要的文件)与以后提交的更改不冲突,则此过程可以完全自动化,并且要求您手动重做以后提交的所有合并和冲突。

    缺点是它仍然需要重写所有后续提交,如果它们已在别处共享则使它们无效,并使提交消息中的提交引用无效,例如由git revert生成的提交。