背景

Git删除某次提交是一件比较难处理的事情,尤其是在两个开发者修改了同一个文件的情况下。本文假设在两个开发者没有修改同一个文件的情况下,总结如何删除其中一个开发者所提交的内容。

假设当前的提交记录是这样的:

gitlab 去除所有的提交记录 gitlab删除某次提交_3c

具体的提交过程是:

提交序号

提交者

提交内容

commit id

第一次提交

ddzhoumin

新增a.txt文件

e3c3121e

第二次提交

choumin

新增b.txt文件

5e6538db

第三次提交

ddzhoumin

修改a.txt文件

67972390

第四次提交

choumin

修改b.txt文件

760bddd8

当前项目中的文件如下所示:

$ ls -l
total 16
-rw-r--r--  1 ddzhoumin  staff  22 11 10 15:39 a.txt
-rw-r--r--  1 ddzhoumin  staff  20 11 10 19:08 b.txt

现在我们要删除用户choumin的提交。有三种方法可以实现。

方法一

使用git rebase,将提交历史rebase到第一次提交。

$ git rebase -i e3c3121e

然后自动弹出编辑器,显示内容如下: 

1 pick 5e6538d feat:添加b.txt
  2 pick 6797239 feat:修改a.txt
  3 pick 760bddd feat:修改b.txt
  4
  5 # Rebase e3c3121..760bddd onto e3c3121 (3 commands)
  6 #
  7 # Commands:
  8 # p, pick <commit> = use commit
  9 # r, reword <commit> = use commit, but edit the commit message
 10 # e, edit <commit> = use commit, but stop for amending
 11 # s, squash <commit> = use commit, but meld into previous commit
 12 # f, fixup <commit> = like "squash", but discard this commit's log message
 13 # x, exec <command> = run command (the rest of the line) using shell
 14 # b, break = stop here (continue rebase later with 'git rebase --continue')
 15 # d, drop <commit> = remove commit
 16 # l, label <label> = label current HEAD with a name
 17 # t, reset <label> = reset HEAD to a label
 18 # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
 19 # .       create a merge commit using the original merge commit's
 20 # .       message (or the oneline, if no original merge commit was
 21 # .       specified). Use -c <commit> to reword the commit message.
 22 #
 23 # These lines can be re-ordered; they are executed from top to bottom.
 24 #
 25 # If you remove a line here THAT COMMIT WILL BE LOST.
 26 #
 27 # However, if you remove everything, the rebase will be aborted.
 28 #
 29 # Note that empty commits are commented out

现在删除用户choumin所产生的两次提交记录,即删除以下两行:

pick 5e6538d feat:添加b.txt
pick 760bddd feat:修改b.txt

保存并退出编辑器,返回命令行后显示如下内容:

$ git rebase -i e3c3121e
Successfully rebased and updated refs/heads/dev.

再看一下当前项目中的文件,如下所示:

$ ls -l
total 8
-rw-r--r--  1 ddzhoumin  staff  22 11 10 19:28 a.txt

最后将删除后的内容强制推送到远程仓库

$ git push --force

现在再看提交记录:

gitlab 去除所有的提交记录 gitlab删除某次提交_git rebase_02

可以看到用户choumin所提交的两次记录已经被删除了。

方法二

使用git format-patch,生成多个patch文件,删除用户choumin的提交patch,并重新应用其他用户的提交patch。其中,-3对应用户choumin的第一次提交到当前最后一次提交的记录数。

$ git format-patch -3
0001-feat-b.txt.patch
0002-feat-a.txt.patch
0003-feat-b.txt.patch

根据邮箱查找出用户choumin的提交patch,即只有0002-feat-a.txt.patch是除用户choumin外其他用户的所有提交patch。

$ grep -irn choumin@localhost *.patch
0001-feat-b.txt.patch:2:From: choumin <choumin@localhost>
0003-feat-b.txt.patch:2:From: choumin <choumin@localhost>

重置当前HEAD为用户choumin最早一次提交的前一次提交

$ git reset --hard e3c3121e
HEAD is now at e3c3121 feat:添加a.txt

依次应用其他用户的patch

$ git am 0002-feat-a.txt.patch
Applying: feat:修改a.txt

删除所有patch文件。

$ ls -l
total 32
-rw-r--r--  1 didi  staff  486 11 10 21:21 0001-feat-b.txt.patch
-rw-r--r--  1 didi  staff  501 11 10 21:21 0002-feat-a.txt.patch
-rw-r--r--  1 didi  staff  490 11 10 21:21 0003-feat-b.txt.patch
-rw-r--r--  1 didi  staff   22 11 10 21:22 a.txt
$ rm *.patch

最后将删除后的内容强制推送到远程仓库 。

$ ls -l
total 8
-rw-r--r--  1 didi  staff  22 11 10 21:22 a.txt
$ git push --force

方法三

使用git cherry-pick,将除用户choumin外的其他所有提交依次应用到最开始的提交上。

首先,重置当前HEAD为用户choumin最早一次提交的前一次提交

$ git reset --hard e3c3121e
HEAD is now at e3c3121 feat:添加a.txt

然后使用cherry-pick依次应用其他用户的提交,在这里只有commit id为67972390的这一个提交。

$ git cherry-pick 67972390
[dev 0ff3457] feat:修改a.txt
 Date: Sun Nov 10 15:39:09 2019 +0800
 1 file changed, 1 insertion(+)

最后将删除后的内容强制推送到远程仓库 。 

$ ls -l
total 8
-rw-r--r--  1 didi  staff  22 11 10 22:55 a.txt
$ git push --force