当我们修改完代码,提交了一个 commit,然后发现改错了,怎么修正?这种情况分为两种:修正最近一次提交,和修正历史多个提交。

修正最近一次提交

如果发现刚刚提交的内容有错误,当场再修改一下再提交一个新 commit 不就可以么?可以是可以,不过还有一个更加优雅和简单的解决方法:

git commit --amend

"amend" 是“修正”的意思。在提交时,如果加上 --amend 参数,Git 不会在当前 commit 上增加 commit,而是会把当前 commit 的内容和暂存区(stageing area)里的最近一次 commit 的内容合并起来后创建一个新的 commit,用这个新的 commit 把之前最新的 commit 替换掉。所以 commit --amend 做的事就是它的字面意思:对最新一条 commit 进行修正。

具体地,比如你发现刚刚的提交中 foo.txt 文件有错别字,你就可以把文件中的错别字修改好之后,输入以下命令:

git add foo.txt
git commit --amend

此时 Git 会把你带到提交信息编辑界面。提交信息默认是最近那次提交时填的信息。你可以修改或者保留它,然后保存退出。然后,你的最新 commit 就被更新了。

需要注意的有一点:commit --amend 并不是直接修改原 commit 的内容,而是如上面动图所示生成一条新的 commit

修正历史多个提交

commit --amend 可以修正最新 commit 的错误,但如果是倒数第二个、第三个 commit 写错了,怎么办?

如果不是最新的 commit 写错,就不能用 commit --amend 来修复了,而是要用 rebase。不过需要给 rebase 也加一个参数:-i

rebase -irebase --interactive 的缩写形式,意为“交互式变基”。

所谓交互式 rebase,就是在 rebase 的操作执行之前,你可以指定要 rebasecommit 链中的哪一个 commit 是否需要进一步修改。

那么你就可以利用这个特点,进行一次原地 rebase。

例如你是在写错了 commit 之后,又提交了一次才发现之前写错了。现在再用 commit --amend 已经晚了,此时就要用 rebase -i 命令了:

git rebase -i HEAD^^

在 Git 中,有两个「偏移符号」:^~

^ 的用法:在 commit 的后面加一个或多个 ^ 号,可以把 commit 往回偏移,偏移的数量是 ^ 的数量。例如:master^ 表示 master 指向的 commit 之前的那个 commitHEAD^^ 表示 HEAD 所指向的 commit 往前数两个 commit

~ 的用法:在 commit 的后面加上 ~ 号和一个数,可以把 commit 往回偏移,偏移的数量是 ~ 号后面的数。例如:HEAD~5 表示 HEAD 指向的 commit往前数 5 个 commit

上面这行代码表示,把当前 commitHEAD 所指向的 commitrebaseHEAD 向前两个的 commit 上:

如果没有 -i 参数的话,这种原地 rebase 相当于空操作,会直接结束。而在加了 -i 后,就会跳到一个新的界面:

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
...

这个编辑界面的最顶部,列出了将要被 rebase 的所有 commits,也就是倒数第二个 commit “第 N-2 次提交”和最近的 commit “第 N-1 次提交”。需要注意,这个排列是正序的,旧的 commit 会排在上面,新的排在下面。

这两行指示了两个信息:需要处理哪些 commit 和如何处理它们。

你需要修改这两行的内容来指定你需要的操作。每个 commit 默认的操作都是 pick,表示直接应用这个 commit。所以如果你现在直接退出编辑界面,那么结果仍然是空操作。

但你的目标是修改倒数第二个 commit,也就是上面的那个“第 N-2 次提交”,所以你需要把它的操作指令从 pick 改成 editedit 的意思是应用这个 commit,然后停下来等待继续修正。其他的操作指令,在这个界面里都已经列举了出来(下面的 "Commands…" 部分文字),你可以自己研究一下。

edit 310154e 第 N-2 次提交
pick a5f4a0d 第 N-1 次提交...

pick 修改成 edit 后,就可以退出编辑界面了,并输出以下信息:

$ git rebase -i HEAD^^
Stopped at 310154e... 第 N-2 次提交
You can amend the commit now, withgit commit --amendOnce you're satisfied with your changes, rungit rebase --continue

上图的提示信息说明,rebase 过程已经停在“第 N-2 次提交”的 commit 的位置,那么现在你就可以去修改你想修改的内容了。

修改完成后,和前文修改最近提交的方法一样,用 commit --amend 把修改原地应用到一个新的 commit

git add foo.txt
git commit --amend

这样你的倒数第二个错误的 commit 就被修正了。在此过程中,把原来倒数第二个 commit 的内容和当前修改的内容合并在一起创建了一个新的 commit,并用此 commit 原地替换了原来的原来倒数第二个 commit:

然后,你可以用 rebase --continue 来继续上述 rebase 过程。

git rebase --continue

所有需要重写的 commit 都修改完成后,这次交互式 rebase 的过程就完美结束了。

总结

只修正最近的错误提交,使用简单的 commit --amend 即可。若修改历史多个提交用交互式变基 rebase -i,它可以在 rebase 开始之前指定一些额外操作。通过交互式变基还可以实现其它历史重写操作,如“重新排序提交”、“压缩提交”、“拆分提交”等,这些历史重写操作不常用,我个人从来没用过,所以就不讲了,你可以在实际有需要的时候自己再去研究一下。

-

精致码农

带你洞悉编程与架构

↑长按图片识别二维码关注,不要错过网海相遇的缘分

Git 常用操作 | 重写 commit 历史相关推荐

  1. git常用操作以及码云Gitee连接git

    文章目录 1 git简介 1.1 工作区.暂存区.版本库 1.2 工作区状态保存 2 和gitee连接 2.1 创建git仓库 2.2 通过ssh公钥连接 2.2.1 获取公钥 2.2.2 gitee ...

  2. Node.js Git Server搭建及Git常用操作笔记

    Node.js Git Server搭建及Git常用操作笔记 安装Git工具即可在本地进行Git仓库的管理,如果要实现远程仓库则需要搭建Git Server.通过Node.js搭建Git Server ...

  3. git 常用操作总结——基于Gitlab

    博主目前在蚂蚁集团-体验技术部,AntV/S2 是博主所在团队的开源项目--多维交叉分析表格,欢迎使用,感谢到 S2 github 仓库点赞 star,有任何关于前端面试.就业.技术问题都可给在文章后 ...

  4. git报错:‘fatal:remote origin already exists‘怎么处理?附上git常用操作以及说明。

    git添加远程库的时候有可能出现如下的错误, 怎么解决? 只要两步: 1.先删除 $ git remote rm origin 2.再次执行添加就可以了. ---------------------- ...

  5. 版本控制工具——Git常用操作(下)

    本文由云+社区发表 作者:工程师小熊 摘要:上一集我们一起入门学习了git的基本概念和git常用的操作,包括提交和同步代码.使用分支.出现代码冲突的解决办法.紧急保存现场和恢复现场的操作.学会以后已经 ...

  6. Git 实用操作 | 撤销 Commit 提交

    有的时候,改完代码提交 commit 后发现写得实在太烂了,连自己的都看不下去,与其修改它还不如丢弃重写.怎么操作呢? 使用 reset 撤销 如果是最近提交的 commit 要丢弃重写可以用 res ...

  7. Git学习总结(22)——Git 常用操作再总结

    一.前言 每一个项目,我们都把他变成一个git仓库.一个git仓库包含无数分支,默认分支为master,每个分支都包含无数个版本库,每个版本库都包含无数个文件. 二.常用操作 $ git co(che ...

  8. Git常用操作速查,没有人比我更简单!!

    目录 Git初始化 Git配置 init clone commit branch push pull checkout merge log rm reset --hard rebase 应用场景 其他 ...

  9. git常用操作及原理--本地

    ​工欲善其事,必先利其器 git是跨平台的,在linux.windows.mac上都能使用的优秀的版本管理工具. git干啥的? 为什么要用git?话不多说,看图: 你是否也有这样的遭遇,文件有很多个 ...

最新文章

  1. ubuntu 启动器
  2. 优化JS加载时间过长的一种思路
  3. Tomcat一步步实现反向代理、负载均衡、内存复制
  4. pat 乙级 1023 组个最小数(C++)
  5. CentOS 7 firewalld使用简介
  6. 【Web】WEB项目初启动的那些糟心事
  7. 栈溢出笔记1.12 栈Cookie
  8. ORA-00054:资源正忙,但指定以nowait方式
  9. Ubuntu 18.04上使用snort3搭建NIDS(一)| 安装篇
  10. Qt对图像的二值化处理
  11. 基于Ubuntu虚拟机的Linux驱动开发入门
  12. python add sheet_Python系列(6)——使用openpyxl将三种类型的数据添加进新sheet及已有的sheet中且不覆盖原数据...
  13. 光电信息科学与工程学c语言吗,光电信息工程专业排名_光电信息科学与工程专业可以考什么专业的研究生...
  14. 服务器怒稳定进不了某个网址,登录服务器的一瞬间,让我感觉自己再也不是“菊外人”...
  15. 2022腾讯云服务器租用费用价格表(轻量和CVM精准报价)
  16. 小程序 设置小程序打开聊天中的素材
  17. 处理txt文件下载下来以后,排版格式不对的问题
  18. 《财务自由之路III》阅读笔记2021-03-18
  19. excel标题行列浮动显示/冻结窗口
  20. 在idea配置虚拟机参数与虚拟机内存溢出

热门文章

  1. h5 端图片上传-模拟多张上传
  2. java 动态代理
  3. Event 事件 - 基础
  4. 简述HTML DOM及其节点分类
  5. java 最后的异常_java – 最后不要抛出堆栈溢出异常
  6. stm32cubeide外部中断_【STM32】HAL库 STM32CubeMX教程三----外部中断(HAL库GPIO讲解)
  7. 机器视觉技术在表面缺陷检测方面的发展趋势
  8. java B2B2C Springcloud多租户电子商城系统-Spring Cloud Sleuth
  9. 使用增量备份修复DG中的GAP
  10. Tomcat定义虚拟主机案例