【问题标题】:How do you remove a specific revision in the git history?如何删除 git 历史记录中的特定修订?
【发布时间】:2018-07-08 20:44:03
【问题描述】:

假设你的 git 历史是这样的:

1 2 3 4 5

1–5 是单独的修订版。您需要在保留 1、2、4 和 5 的同时删除 3。如何做到这一点?

在要删除的一个之后有数百个修订时,有没有一种有效的方法?

【问题讨论】:

  • 这个问题定义不明确。它没有明确说作者想要 1-2-(3+4)-5 或 1-2-4-5
  • 好吧 8 年后,我无法确切地告诉你我试图解决什么问题。但是在 git 中做某事总是有很多方法,而且有很多不同的人喜欢的答案,所以我想这种模棱两可并没有给太多人带来很多困难
  • git rebase --onto 2 3 HEAD 几乎意味着 rebase 到 2,提交在 3 和 HEAD 之间(HEAD 是可选的,或者在这种情况下为 5)

标签: git


【解决方案1】:

根据this comment(我检查了这是真的),rado 的答案非常接近,但让 git 处于分离的头部状态。相反,删除 HEAD 并使用它从您所在的分支中删除 <commit-id>

git rebase --onto <commit-id>^ <commit-id>

【讨论】:

  • 如果您能告诉我如何仅根据 commit-id 从历史记录中删除该 commit-id,那么您就是我的英雄。
  • 您能否在答案中解释魔术命令的作用? IE。每个参数代表什么?
  • 这很棒,但是如果我想删除历史上的第一个提交怎么办? (这就是我来这里的原因:P)
  • 由于某种原因,当我运行它时没有任何反应。但是,将^ 更改为~1 使其工作。
  • 晚了,但我要补充一点,如果您遇到合并冲突,请中止 rebase,然后在最后使用 --strategy-option theirs 重新运行它。
【解决方案2】:

这是一种以非交互方式删除特定&lt;commit-id&gt; 的方法,只知道您要删除的&lt;commit-id&gt;

git rebase --onto <commit-id>^ <commit-id> HEAD

【讨论】:

  • 也为我工作。顺便说一句,^ 运算符是做什么的?是指指定的提交之后的下一次提交吗?
  • @hopia 表示指定提交的(第一个)父级。见“git帮助修订”
  • 查看@kareem 的建议,在他的回答中省略HEAD 以避免头部分离。
  • 比计算返回搜索的提交次数要容易得多。
  • 这很棒,但是如果我想删除历史上的第一个提交怎么办? (这就是我来这里的原因:P)
【解决方案3】:

如前所述,git-rebase(1) 是您的朋友。假设提交在您的 master 分支中,您会这样做:

git rebase --onto master~3 master~2 master

之前:

1---2---3---4---5  master

之后:

1---2---4'---5' master

来自 git-rebase(1):

一系列提交也可以是 用变基移除。如果我们有 以下情况:

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 的参数和 参数可以是任何 有效的提交。

【讨论】:

  • 这不应该是--onto master~3 master~1吗?
  • 如果只是想删除最后一次提交,那就是--onto master~1 master
  • 我想携带这个溶胶。但我收到MERGE CONFLICT 错误。我使用了stackoverflow.com/questions/2938301/remove-specific-commit 中提到的场景,并且无法删除该示例中的第二次提交。
【解决方案4】:

要将修订版 3 和修订版 4 合并为一个修订版,您可以使用 git rebase。如果要删除修订版 3 中的更改,则需要在交互式变基模式下使用编辑命令。如果要将更改合并到一个修订版中,请使用 squash。

我已经成功地使用了这种 squash 技术,但以前从未需要删除修订。 “拆分提交”下的 git-rebase 文档有望为您提供足够的想法来弄清楚。 (或者其他人可能知道)。

来自git documentation

从您想按原样保留的最旧的提交开始:

git rebase -i &lt;after-this-commit&gt;

编辑器将启动当前分支中的所有提交(忽略合并提交),这些提交发生在给定提交之后。您可以将此列表中的提交重新排序为您心中的内容,您可以删除它们。该列表或多或少看起来像这样:

pick deadbee 本次提交的单行
选择 fa1afe1 下一次提交的单行
...

在线描述纯粹是为了您的乐趣; git-rebase 不会查看它们,而是查看提交名称(本例中为“deadbee”和“fa1afe1”),因此不要删除或编辑名称。

通过将命令“pick”替换为命令“edit”,您可以告诉 git-rebase 在应用该提交后停止,以便您可以编辑文件和/或提交消息,修改提交,然后继续变基。

如果您想将两个或多个提交合并为一个,请将命令“pick”替换为“squash”以进行第二次和后续提交。如果提交有不同的作者,它将把压缩的提交归于第一次提交的作者。

【讨论】:

  • -1 问题定义明确,但这个答案不是很清楚。作者没有说具体的解决方案是什么。
  • 这是一个错误的线索。 SPLITTING COMMITS 部分不正确。您想在手册中阅读更高的内容 - 请参阅@Rares Vernica 的答案。
  • @AleksandrLevchuk 这个问题没有很好的定义:从问题的表述方式不清楚是保留还是丢弃 3 中的变更集。我同意,如果要放弃更改,其他答案提供了一种更简单的方法。但是,如果要保留更改,则这将是纯粹的修饰操作。如果其他人的工作基于有缺陷的历史,这两种方法都会以危险的方式改写历史;如果是这种情况,则不应进行外观清理,最好通过 git revert 进行更改删除。
  • 每个人都在抱怨,但这对我有帮助。大声笑
【解决方案5】:

如果您只想删除修订版 3 中所做的更改,您可能需要使用 git revert。

Git revert 只是创建一个新的修订版本,其更改会撤消您正在恢复的修订版本中的所有更改。

这意味着您保留了有关不需要的提交以及删除这些更改的提交的信息。

如果有人可能同时从您的存储库中拉出,这可能会更加友好,因为恢复基本上只是一个标准提交。

【讨论】:

  • 不幸的是,这对我来说不是一个好的解决方案,因为有人不小心向 repo 提交了 100MB 的废话,从而扩大了大小并使 Web 界面变得迟缓。
【解决方案6】:

到目前为止,所有答案都没有解决尾随问题:

有数百次修订时有没有有效的方法 在要删除的那个之后?

步骤如下,但作为参考,我们假设以下历史:

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C: 在要删除的提交之后提交(干净)

R: 要删除的提交

B: 在要删除的提交之前提交(基础)

由于“数百次修订”的限制,我假设以下前提条件:

  1. 有些令人尴尬的提交,你希望永远不存在
  2. 实际上依赖于令人尴尬的提交的后续提交为零(还原时冲突为零)
  3. 你不在乎你会被列为数百个介入提交的“提交者”(“作者”将被保留)
  4. 您从未共享存储库
    • 或者你实际上对所有曾经克隆过包含该提交的历史的人有足够的影响力,以说服他们使用你的新历史
    • 和你don't care关于rewriting history

这是一组非常严格的约束,但有一个有趣的答案实际上适用于这种极端情况。

步骤如下:

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

如果确实没有冲突,那么应该不会再有任何中断。如果有冲突,你可以解决它们并rebase --continue 或决定只是忍受尴尬和rebase --abort

现在您应该在 master 上,其中不再有提交 Rsave 分支指向您之前所在的位置,以防您想要协调。

您希望如何安排其他人转移到您的新历史记录取决于您。您需要熟悉stashreset --hardcherry-pick。并且您可以删除baseremove-mesave 分支

【讨论】:

  • 我怎么能喜欢这个 150000 次?
  • 帮我从一个分支历史的中间依次删除了 3 个提交,其中有人提交了一堆 150mb 文件。
【解决方案7】:

我也遇到了类似的情况。使用下面的命令使用交互式变基,并在选择时删除第 3 次提交。

git rebase -i remote/branch

【讨论】:

    【解决方案8】:

    这就是我遇到的情况,以及我是如何解决的。

    [branch-a]
    
    [Hundreds of commits] -> [R] -> [I]
    

    这里R 是我需要删除的提交,I 是在R 之后的单个提交

    我做了一个还原提交并将它们压缩在一起

    git revert [commit id of R]
    git rebase -i HEAD~3
    

    在交互式 rebase squash 期间,最后 2 次提交。

    【讨论】:

      【解决方案9】:

      rado 和 kareem 的答案对我没有任何作用(只出现消息“当前分支是最新的。”)。这可能是因为 '^' 符号在 Windows 控制台中不起作用。但是,根据this 的评论,将 '^' 替换为 '~1' 解决了问题。

      git rebase --onto <commit-id>^ <commit-id>
      

      【讨论】:

        猜你喜欢
        • 2011-03-31
        • 2020-12-28
        • 2017-06-16
        • 1970-01-01
        • 2023-01-30
        • 2014-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多