有的时候,改完代码提交 commit 后发现写得实在太烂了,连自己的都看不下去,与其修改它还不如丢弃重写。怎么操作呢?

使用 reset 撤销

如果是最近提交的 commit 要丢弃重写可以用 reset 来操作。比如你刚写了一个 commit:

写完回头看了看,你觉得不行这得重新写。那么你可以用 reset --hard 来撤销这条 commit。

git reset --hard HEAD^

HEAD^ 表示往回数一个位置的 commit`,上篇刚说过。

因为你要撤销最新的一个 commit,所以你需要恢复到它的父 commit ,也就是 HEAD^。那么在这行之后,你要丢弃的最新一条就被撤销了:

不过,就像图上显示的,你被撤销的那条提交并没有消失,只是你不再用到它了。如果你在撤销它之前记下了它的 SHA-1 码,那么你还可以通过 SHA-1 来找到他它。

使用 rebase -i 撤销

假如有一个 commit,你在刚把它写完的时候并没有觉得它不好,可是在之后又写了几个提交以后,你突然灵光一现:哎呀,那个 commit 不该写,我要撤销!

不是最新的提交,就不能用 reset --hard 来撤销了。这种情况的撤销,就要用之前介绍过的一个指令交互式变基:rebase -i

之前介绍过,交互式变基可以用来修改某些旧的 commit。其实除了修改提交,它还可以用于撤销提交。比如下面这种情况:

你想撤销倒数第二条 commit,那么可以使用 rebase -i

git rebase -i HEAD^^

Git 引导到选择要操作的 commit 页面:

pick 310154e 第 N-2 次提交
pick a5f4a0d 第 N-1 次提交 # Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# 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
...

在上篇中,讲到要修改哪个 commit 就把哪个 commit 前面的 pick 改成 edit。而如果你要撤销某个 commit ,做法就更加简单粗暴一点:直接删掉这一行就好(使用 d 命令)。

pick a5f4a0d 第 N-1 次提交

# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# 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
...

把这一行删掉就相当于在 rebase 的过程中跳过了这个 commit,从而也就把这个 commit 丢弃了。

如果你通过 git log 查看,就会发现之前的倒数第二条 commit 已经不在了。

使用用 rebase --onto 撤销

除了用交互式 rebase,你还可以用 rebase --onto 来更简便地撤销提交。

rebase 加上 --onto 选项之后,可以指定 rebase 的「起点」。一般的 rebase, 的「起点」是自动选取的,选取的是当前 commit 和目标 commit 在历史上的交叉点。

例如下面这种情况:

如果在这里执行:

git rebase 第3个commit

那么 Git 会自动选取 35 的历史交叉点 2 作为 rebase 的起点,依次将 45 重新提交到 3 的路径上去。

--onto 参数,就可以额外给 rebase 指定它的起点。例如同样以上图为例,如果我只想把 5 提交到 3 上,不想附带上 4,那么我可以执行:

git rebase --onto 第3个commit 第4个commit branch1

选项 --onto 参数后面有三个附加参数:目标 commit、起点 commit(注意:rebase 的时候会把起点排除在外)、终点 commit。所以上面这行指令就会从 4 往下数,拿到 branch1 所指向的 5,然后把 5 重新提交到 3 上去。

同样的,你也可以用 rebase --onto 来撤销提交:

git rebase --onto HEAD^^ HEAD^ branch1

上面这行代码的意思是:以倒数第二个 commit 为起点(起点不包含在 rebase 序列里),branch1 为终点,rebase 到倒数第三个 commit 上。

也就是这样:

总结

撤销最近一次的 commit 直接使用 reset --hard,撤销过往历史提交。方法有两种:

  1. git rebase -i 在编辑界面中删除想撤销的 commit
  2. git rebase --onto 在 rebase 命令中直接剔除想撤销的 commit

这有两种理念是一样的,即在 rebase 的过程中去掉想撤销的 commit,让它消失在历史中。

最新文章

  1. 客户端实现蓝牙接收(C#)
  2. 在jsp中默认写上的一段java代码表示basePath 的路径的具体的意思是什么?
  3. 如何远程断点调试本地localhost项目
  4. Tableau学习笔记之五
  5. tomcat安全配置之证书密码加密存储
  6. slide from one widget to another
  7. Kqueue与epoll机制
  8. 根据当前登录域账号 获取AD用户姓名和所在OU目录
  9. 深入理解viewport(转)
  10. phpstudy中的mysql
  11. Android的自定义View及View的绘制流程
  12. 在OSGI容器Equinox中嵌入HttpServer
  13. commons-lang3-3.2.jar中的常用工具类的使用
  14. 洛谷 P2440 木材加工【基础二分】
  15. android-------- 多渠道打包(借助友盟移动统计分析)
  16. r-mq实现顺序消费,不重复消费
  17. SwitchHosts—hosts管理工具
  18. ping和telnet
  19. postman 定义并使用全局变量
  20. JAVA补充-抽象类

热门文章

  1. Django中manage.py migrate无效的问题
  2. C#算法设计排序篇之03-直接插入排序(附带动画演示程序)
  3. C#LeetCode刷题之#202-快乐数(Happy Number)
  4. Flask实现RESTful API(注意参数位置解析)
  5. 题解 BZOJ4709
  6. SQL Server 异常代码处理
  7. (转载)sqlserver2008”备份集中的数据库备份与现有的XX数据库不同”解决办法
  8. 土地购买 (斜率优化dp)
  9. JVM对象分配
  10. RSA非对称加密(java实例代码)