背景
Git删除某次提交是一件比较难处理的事情,尤其是在两个开发者修改了同一个文件的情况下。本文假设在两个开发者没有修改同一个文件的情况下,总结如何删除其中一个开发者所提交的内容。
假设当前的提交记录是这样的:
具体的提交过程是:
提交序号 | 提交者 | 提交内容 | 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
现在再看提交记录:
可以看到用户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