I was working with a friend on a project, and he edited a bunch of files that shouldn't have been edited. Somehow I merged his work into mine, either when I pulled it, or when I tried to just pick the specific files out that I wanted. I've been looking and playing for a long time, trying to figure out how to remove the commits that contain the edits to those files, it seems to be a toss up between revert and rebase, and there are no straightforward examples, and the docs assume I know more than I do.

下面是这个问题的简化版本:

给定下面的场景,我如何删除提交2?

$ mkdir git_revert_test && cd git_revert_test

$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/

$ echo "line 1" > myfile

$ git add -A

$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 myfile

$ echo "line 2" >> myfile

$ git commit -am "commit 2"
[master 342f9bb] commit 2
 1 files changed, 1 insertions(+), 0 deletions(-)

$ echo "line 3" >> myfile

$ git commit -am "commit 3"
[master 1bcb872] commit 3
 1 files changed, 1 insertions(+), 0 deletions(-)

预期的结果是

$ cat myfile
line 1
line 3

以下是我一直试图恢复的一个例子

$ git revert 342f9bb
Automatic revert failed.  After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.

当前回答

你的选择是

保留错误并引入修复 删除错误并更改历史记录。

您应该选择(1)如果错误的更改已被其他人拾取,以及(2)如果错误仅限于一个私有的未推送分支。

Git revert是一个自动执行(1)的工具,它创建了一个新的提交,撤销了之前的一些提交。您将在项目历史中看到错误和删除,但是从您的存储库中提取的人在更新时不会遇到问题。在你的例子中,它不是以自动的方式工作的,所以你需要编辑'myfile'(删除第2行),git添加myfile和git提交来处理冲突。然后,历史记录中将有四个提交,提交4将还原提交2。

如果没有人关心你的历史改变,你可以重写它并删除提交2(选择2)。最简单的方法是使用git rebase -i 8230fa3。这将使您进入一个编辑器,您可以通过删除提交来选择不包括错误的提交(并将“pick”放在其他提交消息旁边)。仔细研究一下这样做的后果。

其他回答

你可以使用git rebase删除不需要的提交。 假设您将同事的topic分支的一些提交包含到您的topic分支中,但后来决定不需要这些提交。

git checkout -b tmp-branch my-topic-branch  # Use a temporary branch to be safe.
git rebase -i master  # Interactively rebase against master branch.

此时,文本编辑器将打开交互式rebase视图。例如

通过删除它们的行来删除您不想要的提交 保存并退出

如果改基不成功,删除临时分支并尝试其他策略。否则,请继续执行以下说明。

git checkout my-topic-branch
git reset --hard tmp-branch  # Overwrite your topic branch with the temp branch.
git branch -d tmp-branch  # Delete the temporary branch.

如果将主题分支推到远程,可能需要强制推,因为提交历史已经更改。如果其他人在同一个分支上工作,给他们提个醒。

这里有一个快速的例子,如何用egit做到这一点:

我想删除我添加文件的提交 右键点击要删除的文件之前的提交,选择“interactive rebase” 在rebase视图中选择commit three并单击上面的跳过图标。在胡佛这个图标,它告诉你提交将被删除。 点击start rebase。 进入git staging,点击push。 在弹出窗口,出现点击力量和前进 在此之后,您可以看到提交已被删除。

你的选择是

保留错误并引入修复 删除错误并更改历史记录。

您应该选择(1)如果错误的更改已被其他人拾取,以及(2)如果错误仅限于一个私有的未推送分支。

Git revert是一个自动执行(1)的工具,它创建了一个新的提交,撤销了之前的一些提交。您将在项目历史中看到错误和删除,但是从您的存储库中提取的人在更新时不会遇到问题。在你的例子中,它不是以自动的方式工作的,所以你需要编辑'myfile'(删除第2行),git添加myfile和git提交来处理冲突。然后,历史记录中将有四个提交,提交4将还原提交2。

如果没有人关心你的历史改变,你可以重写它并删除提交2(选择2)。最简单的方法是使用git rebase -i 8230fa3。这将使您进入一个编辑器,您可以通过删除提交来选择不包括错误的提交(并将“pick”放在其他提交消息旁边)。仔细研究一下这样做的后果。

我有一个简单的解决方案,使用补丁恢复您所有的更改。

检查当前的主要分支机构(例如开发)

git checkout develop

在历史日志中查找你的commit-id,只签出你对一个新分支的更改:

git log
git checkout -b your-branch <your-commit-id>

在你的分支中查找,找到你想要恢复到的前一个状态:

git checkout -b prev-status <previous-commit-id>

创建一个补丁,可以恢复您的所有更改:

git diff your-branch..prev-status > reverts.patch
# the comparing order of branches is important

检查当前的头分支,并应用恢复补丁

git checkout origin develop
git apply reverts.patch
git add *
git commit -m "revert all my changes"

所以你做了一些工作并推动了它,我们称之为提交A和b。你的同事也做了一些工作,提交C和d。你将你同事的工作合并到你的工作中(合并提交E),然后继续工作,也提交了(提交F),然后发现你的同事修改了一些他不应该修改的东西。

你的提交历史是这样的:

A -- B -- C -- D -- D' -- E -- F

你真的想摆脱C D D'既然你说你将同事的工作合并到你的工作中,这些提交已经“存在”了,所以使用git rebase等方法删除这些提交是不可以的。相信我,我试过了。

现在,我看到了两条出路:

if you haven't pushed E and F to your coworker or anyone else (typically your "origin" server) yet, you could still remove those from the history for the time being. This is your work that you want to save. This can be done with a git reset D' (replace D' with the actual commit hash that you can obtain from a git log At this point, commits E and F are gone and the changes are uncommitted changes in your local workspace again. At this point I would move them to a branch or turn them into a patch and save it for later. Now, revert your coworker's work, either automatically with a git revert or manually. When you've done that, replay your work on top of that. You may have merge conflicts, but at least they'll be in the code you wrote, instead of your coworker's code. If you've already pushed the work you did after your coworker's commits, you can still try and get a "reverse patch" either manually or using git revert, but since your work is "in the way", so to speak you'll probably get more merge conflicts and more confusing ones. Looks like that's what you ended up in...