如何删除git历史记录中的特定修订?

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

< p > 1 2 3. 4 5 < / p >

1-5是单独的修订。你需要删除3,同时仍然保持1、2、4和5。如何做到这一点呢?

当一个要删除的版本之后还有数百个版本时,有没有有效的方法?

127845 次浏览

要将版本3和4合并为一个版本,可以使用git rebase。如果您想删除版本3中的更改,您需要在交互式rebase模式下使用edit命令。如果您希望将这些更改合并到单个修订中,请使用squash。

我曾经成功地使用过这种挤压技术,但以前从未需要删除修订。“拆分提交”下的git-rebase文档希望能给您足够的理解。(或者其他人可能知道)。

git文档:

从你想保留的最老的提交开始:

git rebase -i <after-this-commit>

编辑器将被启动,其中包含当前分支中的所有提交(忽略合并提交),合并提交紧跟在给定的提交之后。您可以根据自己的意愿对列表中的提交进行重新排序,也可以删除它们。这个列表大致是这样的:

pick deadbee该提交的一行
pick fa1afe1下一次提交的一行
…< / pre > < /引用>


这一行描述纯粹是为了让你高兴;Git-rebase不会查看它们,而是查看提交名称(本例中为"deadbee"和"fa1afe1"),因此不要删除或编辑这些名称。

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

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

如果你想要做的只是删除在版本3中所做的更改,你可能想要使用git revert。

Git恢复只是创建一个新的版本,其中包含撤销正在恢复的版本中所有更改的更改。

这意味着,您保留了关于不需要的提交和删除这些更改的提交的信息。

如果在同一时间有人从您的存储库中取出数据,这可能会友好得多,因为恢复基本上只是一个标准的提交。

下面是一种非交互式地删除特定<commit-id>的方法,只知道你想删除的<commit-id>:

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

如前所述,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):

一个提交范围也可以是 删除与rebase。如果我们有 以下情况:< / p >

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的一部分。 注意参数to -onto和 参数可以为任意值 有效的commit-ish。< / p >

到目前为止,所有的答案都没有解决后面的问题:

当有数百个修订时,是否有有效的方法 在要删除的那个之后?< / p >

以下是步骤,但为了参考,让我们假设历史记录如下:

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]
< p > C: 在Commit to be removed (clean)

之后提交 < p > R: 要删除的提交

< p > B:

.

.

.

.

由于“数百个修订”的限制,我假设以下先决条件:

  1. 有些尴尬的事情你希望从未发生过
  2. 没有后续的提交实际上依赖于这个尴尬的提交(在恢复时没有冲突)
  3. 你不关心你将被列为数百个介入提交的“Committer”(“Author”将被保留)
  4. 您从未共享过存储库
    • 或者你实际上有足够的影响力说服所有克隆历史的人使用你的新历史
    • 和你不关心关于改写历史
    • 李< / ul > < / >

这是一组非常严格的约束条件,但在这种情况下,有一个有趣的答案。

以下是步骤:

  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上,里面不再有commit Rsave分支指向你之前所在的位置,以防你想要和解。

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

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

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

这就是我面对的情况,以及我是如何解决它的。

[branch-a]


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

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

我做了一个回复提交,并把它们压在一起

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

在交互重基期间,压缩最后2次提交。

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

git rebase -i remote/branch

收音机和kareem的回答对我没有任何帮助(只有消息“当前分支是最新的。”出现)。这可能是因为'^'符号在Windows控制台中不起作用。然而,根据注释,将'^'替换为'~1'可以解决这个问题。

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