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 revert—strategy resolve <commit>
严厉的方式,完全删除只有最后一个提交:
git重置-软“头^”
注意:避免git重置——很难,因为它也会丢弃自上次提交以来文件中的所有更改。如果——软的不行,那就试试——混合的或者——保留的。
Rebase(显示最近5次提交的日志并删除你不想要的行,或重新排序,或将多个提交压缩在一个文件中,或做任何你想做的事情,这是一个非常通用的工具):
git rebase -i HEAD~5
如果犯了错误:
git rebase --abort
快速rebase:只删除使用id的特定提交:
Git rebase—to commit-id^ commit-id
替代方案:你还可以试试:
Git选择commit-id
还有另一种选择:
Git恢复——不提交
作为最后的手段,如果你需要完全自由的历史编辑(例如,因为git不允许你编辑你想要的内容),你可以使用这个非常快速的开源应用程序:reposurgeon。
注意:当然,所有这些更改都是在本地完成的,你应该在git push之后将更改应用到远程。如果你的repo不想删除提交(“不允许快进”,当你想删除已经提交的提交时就会发生),你可以使用git push -f强制推送更改。
注2:如果在一个分支上工作,你需要强制push,你应该绝对避免git push——force,因为这可能会覆盖其他分支(如果你对它们做了更改,即使你当前的签出是在另一个分支上)。当你强制push时,最好总是指定远程分支:git push——force origin your_branch。
方法1
首先获取需要恢复的提交散列(例如:1406cd61)。简单的修复将在命令之下,
$ git revert 1406cd61
如果你在1406cd61文件提交后提交了更多与1406cd61文件相关的更改,上述简单命令将无法工作。然后你要做下面的步骤,也就是摘樱桃。
方法2
请遵循下面的操作顺序,因为我们正在使用——force,您需要对git回购有管理权限才能做到这一点。
步骤1:找到要删除git日志的提交前的提交
步骤2:签出提交git Checkout <commit hash>
步骤3:使用当前的checkout commit git checkout -b <new branch>创建一个新的分支
第4步:现在你需要在移除commit git cherry-pick <commit hash>之后添加commit
步骤5:现在对所有想要保留的提交重复步骤4。
步骤6:将所有提交添加到新分支并提交之后。检查所有东西是否处于正确的状态并按预期工作。再次检查已提交的所有内容:git状态
步骤7:切换到你的broken branch git checkout <broken branch>
第8步:现在执行一个硬重置,在你想要删除git重置之前的提交分支上——hard <commit hash>
步骤9:将固定的分支合并到这个分支git Merge <分支名称>
步骤10:将合并的更改推回原点。警告:这将覆盖远程回购!Git push——force origin <分支名称>
您可以在不创建新分支的情况下执行该过程,将步骤2和步骤3替换为步骤8,然后不执行步骤7和步骤9。
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>
它应该能更好地理解你的意思。我不知道可用的策略列表是什么,也不知道任何策略的定义。