前提

这里假设remote都是origin ,分支都为master。
注意:如果想单独删除git某个已经push的提交,那就只能删除最近的那个commit,而无法删除倒数第二个commit,而保留倒数第一个提交,如下
假设有A->B->C 三个提交,我们没法只删除B,而保留C,虽然可以通过rebase的方式实现,但是rebase过程中一堆冲突,对于大点的项目,很难实际操作。
我们只能删除B以及它之后的所有commit,即把B、C都删除,结果为 A。

方法一:git reset

先删除本地的:
git reset –hard  <commit hash>
然后push到remote:
git  push -f
但是为了安全,建议使用:
git  push –force-with-lease

方法二:git rebase

假设我们有3次提交:
$ git log –pretty=oneline –abbrev-commit
735293c  commit 2
f38f353 commit 1
2df3c7c Initial commit
“commit 2”是最近的一次commit,而我们想要删除“commit 1”以及它之后的所有提交。
我们使用:
$git rebase -i f38f353 ^   // f38f353为commit 1的hash
-i :表示进行交互式的rebase操作。
^:表示hash之前的提交
上面的命令会使用默认的文本编辑器(默认为vi)打开最近的两次commit ,如下:
pick f38f353 commit 1
pick 735293c commit 2

# Rebase 2df3c7c..735293c onto 2df3c7c (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.

 

vi打开的文本文件里有2个最新的记录,找到我们要删除的那行记录,通过vi操作,将文档中以“ pick xxx …” 开头的行都删掉,删掉后如下:
# Rebase 2df3c7c..735293c onto 2df3c7c (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.

 

然后用vi保存。
此时再查看本地的提交记录,发现成功删除了 “commit 1”以及它之后的所有提交记录。如下:
$ git log –pretty=oneline –abbrev-commit
2df3c7c (HEAD) Initial commit
最后,将本地修改推送到远程,将远程上错误提交也删除:
$ git push origin +master     // 或者   git   push -f
+:表示强制 non-fastforward push

方法三: git push

假设有如下提交记录:
$ git log –pretty=oneline –abbrev-commit
cf8f080 (HEAD -> master, origin/master) commit 3
92b3abb commit 20
f38f353 commit 1
2df3c7c Initial commit
假设我们要删除“f38f353 commit”之后的提交,执行如下命令:
$ git push origin +92b3abb^:master
92b3abb^:表示只保留92b3abb之前的提交
+:表示强制 non-fastforward push
此时,时间线如下:
可以看到远程的提交记录已经改变,本地的提交记录还是旧的,这些本地的多余提交,我们也可以使用git  reset –hard方法删掉。
总结:
删除已经push的提交是很危险的,因为如果是多人协作的,你不能保证你本地的分支一定是最新的,这样就可能把旧的代码push到远程,这可能会把别人的最新代码给删了。
参考:

 

One thought on “git如何删除已经push到远程的提交”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.