前提
这里假设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到远程,这可能会把别人的最新代码给删了。
参考:
文章不错支持一下吧