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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 05:44:11  来源:igfitidea点击:

How do you remove a specific revision in the git history?

git

提问by 1800 INFORMATION

Suppose your git history looks like this:

假设您的 git 历史记录如下所示:

1 2 3 4 5

1 2 3 4 5

1–5 are separate revisions. You need to remove 3 while still keeping 1, 2, 4 and 5. How can this be done?

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

Is there an efficient method when there are hundreds of revisions after the one to be deleted?

删除后有数百个修订版,有没有有效的方法?

采纳答案by garethm

To combine revision 3 and 4 into a single revision, you can use git rebase. If you want to remove the changes in revision 3, you need to use the edit command in the interactive rebase mode. If you want to combine the changes into a single revision, use squash.

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

I have successfully used this squash technique, but have never needed to remove a revision before. The git-rebase documentation under "Splitting commits" should hopefully give you enough of an idea to figure it out. (Or someone else might know).

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

From the git documentation:

git 文档

Start it with the oldest commit you want to retain as-is:

git rebase -i <after-this-commit>

An editor will be fired up with all the commits in your current branch (ignoring merge commits), which come after the given commit. You can reorder the commits in this list to your heart's content, and you can remove them. The list looks more or less like this:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

The oneline descriptions are purely for your pleasure; git-rebase will not look at them but at the commit names ("deadbee" and "fa1afe1" in this example), so do not delete or edit the names.

By replacing the command "pick" with the command "edit", you can tell git-rebase to stop after applying that commit, so that you can edit the files and/or the commit message, amend the commit, and continue rebasing.

If you want to fold two or more commits into one, replace the command "pick" with "squash" for the second and subsequent commit. If the commits had different authors, it will attribute the squashed commit to the author of the first commit.

从你想保持原样的最旧提交开始:

git rebase -i <after-this-commit>

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

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

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

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

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

回答by kareem

Per this comment(and I checked that this is true), rado's answer is very close but leaves git in a detached head state. Instead, remove HEADand use this to remove <commit-id>from the branch you're on:

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

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

回答by rado

Here is a way to remove non-interactively a specific <commit-id>, knowing only the <commit-id>you would like to remove:

这是一种以非交互方式删除特定 的方法<commit-id>,只知道<commit-id>您要删除的 :

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

回答by rvernica

As noted before git-rebase(1)is your friend. Assuming the commits are in your masterbranch, you would do:

如前所述git-rebase(1)是你的朋友。假设提交在您的master分支中,您将执行以下操作:

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

Before:

前:

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

After:

后:

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

From git-rebase(1):

来自 git-rebase(1):

A range of commits could also be removed with rebase. If we have the following situation:

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

then the command

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

would result in the removal of commits F and G:

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

This is useful if F and G were flawed in some way, or should not be part of topicA. Note that the argument to --onto and the parameter can be any valid commit-ish.

也可以使用 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。

回答by SpoonMeiser

If all you want to do is remove the changes made in revision 3, you might want to use git revert.

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

Git revert simply creates a new revision with changes that undo all of the changes in the revision you are reverting.

Git revert 只是创建一个新的修订版本,其中的更改会撤消您要还原的修订版本中的所有更改。

What this means, is that you retain information about both the unwanted commit, and the commit that removes those changes.

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

This is probably a lot more friendly if it's at all possible the someone has pulled from your repository in the mean time, since the revert is basically just a standard commit.

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

回答by jdsumsion

All the answers so far don't address the trailing concern:

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

Is there an efficient method when there are hundreds of revisions after the one to be deleted?

删除后有数百个修订版,有没有有效的方法?

The steps follow, but for reference, let's assume the following history:

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

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

C: commit just following the commit to be removed (clean)

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

R: The commit to be removed

R:要删除的提交

B: commit just preceding the commit to be removed (base)

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

Because of the "hundreds of revisions" constraint, I'm assuming the following pre-conditions:

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

  1. there is some embarrassing commit that you wish never existed
  2. there are ZERO subsequent commits that actually depend on that embarassing commit (zero conflicts on revert)
  3. you don't care that you will be listed as the 'Committer' of the hundreds of intervening commits ('Author' will be preserved)
  4. you have never shared the repository
    • or you actually have enough influence over all the people who have ever cloned history with that commit in it to convince them to use your new history
    • and you don't careabout rewriting history
  1. 有一些令人尴尬的承诺,你希望永远不会存在
  2. 有零个后续提交实际上依赖于那个令人尴尬的提交(还原时零冲突)
  3. 你不在乎你会被列为数百个介入提交的“提交者”(“作者”将被保留)
  4. 您从未共享过存储库
    • 或者你实际上对所有曾经克隆过历史的人有足够的影响力去说服他们使用你的新历史
    • 不关心有关改写历史

This is a pretty restrictive set of constraints, but there is an interesting answer that actually works in this corner case.

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

Here are the steps:

以下是步骤:

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

If there are truly no conflicts, then this should proceed with no further interruptions. If there are conflicts, you can resolve them and rebase --continueor decide to just live with the embarrassment and rebase --abort.

如果确实没有冲突,则不应进一步中断。如果存在冲突,您可以解决它们,rebase --continue或者决定忍受尴尬和rebase --abort.

Now you should be on masterthat no longer has commit Rin it. The savebranch points to where you were before, in case you want to reconcile.

现在你应该master知道不再有提交R了。该save分支点到你之前在哪里,如果你想调和。

How you want to arrange everyone else's transfer over to your new history is up to you. You will need to be acquainted with stash, reset --hard, and cherry-pick. And you can delete the base, remove-me, and savebranches

您想如何安排其他人转移到您的新历史记录取决于您。您将需要与相识stashreset --hardcherry-pick。你可以删除baseremove-mesave分支机构

回答by Sankalp

I also landed in a similar situation. Use interactive rebase using the command below and while selecting, drop 3rd commit.

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

git rebase -i remote/branch

回答by Gautam

So here is the scenario that I faced, and how I solved it.

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

[branch-a]

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

here Ris the commit that I needed to be removed, and Iis a single commit that comes after R

R是我需要删除的提交,并且I是之后的单个提交R

I made a revert commit and squashed them together

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

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

During the interactive rebase squash the last 2 commits.

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

回答by fdermishin

Answers of rado and kareem do nothing for me (only message "Current branch is up to date." appears). Possibly this happens because '^' symbol doesn't work in Windows console. However, according to thiscomment, replacing '^' by '~1' solves the problem.

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

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