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.
Git在计算要恢复的差异时使用的算法需要这样做
任何以后的提交都不会修改被还原的行。
在以后的历史中没有任何其他“相邻”提交。
“相邻”的定义基于上下文差异的默认行数,即3。如果'myfile'是这样构造的:
$ cat >myfile <<EOF
line 1
junk
junk
junk
junk
line 2
junk
junk
junk
junk
line 3
EOF
$ git add myfile
$ git commit -m "initial check-in"
1 files changed, 11 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ perl -p -i -e 's/line 2/this is the second line/;' myfile
$ git commit -am "changed line 2 to second line"
[master d6cbb19] changed line 2
1 files changed, 1 insertions(+), 1 deletions(-)
$ perl -p -i -e 's/line 3/this is the third line/;' myfile
$ git commit -am "changed line 3 to third line"
[master dd054fe] changed line 3
1 files changed, 1 insertions(+), 1 deletions(-)
$ git revert d6cbb19
Finished one revert.
[master 2db5c47] Revert "changed line 2"
1 files changed, 1 insertions(+), 1 deletions(-)
然后一切都按预期工作。
第二个答案非常有趣。有一个尚未正式发布的特性(尽管在Git v1.7.2-rc2中可用)称为恢复策略。你可以像这样调用git:
Git revert—strategy resolve <commit>
它应该能更好地理解你的意思。我不知道可用的策略列表是什么,也不知道任何策略的定义。
我有一个简单的解决方案,使用补丁恢复您所有的更改。
检查当前的主要分支机构(例如开发)
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"
听起来好像坏提交在某个时候被合并提交了。你的合并提交被拉回来了吗?如果是,那么你将使用git revert;你必须咬紧牙关,克服矛盾。如果不是,那么您可以选择rebase或revert,但是您可以在合并提交之前这样做,然后重做合并。
There's not much help we can give you for the first case, really. After trying the revert, and finding that the automatic one failed, you have to examine the conflicts and fix them appropriately. This is exactly the same process as fixing merge conflicts; you can use git status to see where the conflicts are, edit the unmerged files, find the conflicted hunks, figure out how to resolve them, add the conflicted files, and finally commit. If you use git commit by itself (no -m <message>), the message that pops up in your editor should be the template message created by git revert; you can add a note about how you fixed the conflicts, then save and quit to commit.
对于第二种情况,在合并之前修复问题,有两个子情况,这取决于合并后您是否做了更多的工作。如果你还没有,你可以简单地git重置-硬头^取消合并,做还原,然后重新合并。但我猜你有。所以,你最终会这样做:
在合并之前创建一个临时分支,并签出它
进行还原(或使用git rebase -i <something before bad commit> <temporary branch>来删除bad commit)
重做合并
将你的后续工作重新基于:git Rebase—to <临时分支> <旧合并提交> <实际分支>
移除临时分支